Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9ed551e

Browse files
committed
Add conninfo to pg_stat_wal_receiver
Commitb1a9bad introduced a stats view to provide insight into therunning WAL receiver, but neglected to include the connection string init, as reported by Michaël Paquier. This commit fixes that omission.(Any security-sensitive information is not disclosed).While at it, close the mild security hole that we were exposing thepassword in the connection string in shared memory. This isn'tuser-accessible, but it still looks like a good idea to avoid having thecleartext password in memory.Author: Michaël Paquier, Álvaro HerreraReview by: Vik FearingDiscussion:https://www.postgresql.org/message-id/CAB7nPqStg4M561obo7ryZ5G+fUydG4v1Ajs1xZT1ujtu+woRag@mail.gmail.com
1 parentb32e635 commit9ed551e

File tree

7 files changed

+122
-39
lines changed

7 files changed

+122
-39
lines changed

‎doc/src/sgml/monitoring.sgml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,14 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
13021302
<entry><type>text</></entry>
13031303
<entry>Replication slot name used by this WAL receiver</entry>
13041304
</row>
1305+
<row>
1306+
<entry><structfield>conn_info</></entry>
1307+
<entry><type>text</></entry>
1308+
<entry>
1309+
Connection string used by this WAL receiver,
1310+
with security-sensitive fields obfuscated.
1311+
</entry>
1312+
</row>
13051313
</tbody>
13061314
</tgroup>
13071315
</table>

‎src/backend/catalog/system_views.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,8 @@ CREATE VIEW pg_stat_wal_receiver AS
681681
s.last_msg_receipt_time,
682682
s.latest_end_lsn,
683683
s.latest_end_time,
684-
s.slot_name
684+
s.slot_name,
685+
s.conn_info
685686
FROM pg_stat_get_wal_receiver() s
686687
WHEREs.pidIS NOT NULL;
687688

‎src/backend/replication/libpqwalreceiver/libpqwalreceiver.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include<sys/time.h>
2121

2222
#include"libpq-fe.h"
23+
#include"pqexpbuffer.h"
2324
#include"access/xlog.h"
2425
#include"miscadmin.h"
2526
#include"replication/walreceiver.h"
@@ -47,6 +48,7 @@ static char *recvBuf = NULL;
4748

4849
/* Prototypes for interface functions */
4950
staticvoidlibpqrcv_connect(char*conninfo);
51+
staticchar*libpqrcv_get_conninfo(void);
5052
staticvoidlibpqrcv_identify_system(TimeLineID*primary_tli);
5153
staticvoidlibpqrcv_readtimelinehistoryfile(TimeLineIDtli,char**filename,char**content,int*len);
5254
staticboollibpqrcv_startstreaming(TimeLineIDtli,XLogRecPtrstartpoint,
@@ -74,6 +76,7 @@ _PG_init(void)
7476
walrcv_disconnect!=NULL)
7577
elog(ERROR,"libpqwalreceiver already loaded");
7678
walrcv_connect=libpqrcv_connect;
79+
walrcv_get_conninfo=libpqrcv_get_conninfo;
7780
walrcv_identify_system=libpqrcv_identify_system;
7881
walrcv_readtimelinehistoryfile=libpqrcv_readtimelinehistoryfile;
7982
walrcv_startstreaming=libpqrcv_startstreaming;
@@ -117,6 +120,55 @@ libpqrcv_connect(char *conninfo)
117120
PQerrorMessage(streamConn))));
118121
}
119122

123+
/*
124+
* Return a user-displayable conninfo string. Any security-sensitive fields
125+
* are obfuscated.
126+
*/
127+
staticchar*
128+
libpqrcv_get_conninfo(void)
129+
{
130+
PQconninfoOption*conn_opts;
131+
PQconninfoOption*conn_opt;
132+
PQExpBufferDatabuf;
133+
char*retval;
134+
135+
Assert(streamConn!=NULL);
136+
137+
initPQExpBuffer(&buf);
138+
conn_opts=PQconninfo(streamConn);
139+
140+
if (conn_opts==NULL)
141+
ereport(ERROR,
142+
(errmsg("could not parse connection string: %s",
143+
_("out of memory"))));
144+
145+
/* build a clean connection string from pieces */
146+
for (conn_opt=conn_opts;conn_opt->keyword!=NULL;conn_opt++)
147+
{
148+
boolobfuscate;
149+
150+
/* Skip debug and empty options */
151+
if (strchr(conn_opt->dispchar,'D')||
152+
conn_opt->val==NULL||
153+
conn_opt->val[0]=='\0')
154+
continue;
155+
156+
/* Obfuscate security-sensitive options */
157+
obfuscate=strchr(conn_opt->dispchar,'*')!=NULL;
158+
159+
appendPQExpBuffer(&buf,"%s%s=%s",
160+
buf.len==0 ?"" :" ",
161+
conn_opt->keyword,
162+
obfuscate ?"********" :conn_opt->val);
163+
}
164+
165+
PQconninfoFree(conn_opts);
166+
167+
retval=PQExpBufferDataBroken(buf) ?NULL :pstrdup(buf.data);
168+
termPQExpBuffer(&buf);
169+
returnretval;
170+
}
171+
120172
/*
121173
* Check that primary's system identifier matches ours, and fetch the current
122174
* timeline ID of the primary.

‎src/backend/replication/walreceiver.c

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ boolhot_standby_feedback;
7575

7676
/* libpqreceiver hooks to these when loaded */
7777
walrcv_connect_typewalrcv_connect=NULL;
78+
walrcv_get_conninfo_typewalrcv_get_conninfo=NULL;
7879
walrcv_identify_system_typewalrcv_identify_system=NULL;
7980
walrcv_startstreaming_typewalrcv_startstreaming=NULL;
8081
walrcv_endstreaming_typewalrcv_endstreaming=NULL;
@@ -192,6 +193,7 @@ void
192193
WalReceiverMain(void)
193194
{
194195
charconninfo[MAXCONNINFO];
196+
char*tmp_conninfo;
195197
charslotname[NAMEDATALEN];
196198
XLogRecPtrstartpoint;
197199
TimeLineIDstartpointTLI;
@@ -282,7 +284,9 @@ WalReceiverMain(void)
282284

283285
/* Load the libpq-specific functions */
284286
load_file("libpqwalreceiver", false);
285-
if (walrcv_connect==NULL||walrcv_startstreaming==NULL||
287+
if (walrcv_connect==NULL||
288+
walrcv_get_conninfo==NULL||
289+
walrcv_startstreaming==NULL||
286290
walrcv_endstreaming==NULL||
287291
walrcv_identify_system==NULL||
288292
walrcv_readtimelinehistoryfile==NULL||
@@ -304,6 +308,21 @@ WalReceiverMain(void)
304308
walrcv_connect(conninfo);
305309
DisableWalRcvImmediateExit();
306310

311+
/*
312+
* Save user-visible connection string. This clobbers the original
313+
* conninfo, for security.
314+
*/
315+
tmp_conninfo=walrcv_get_conninfo();
316+
SpinLockAcquire(&walrcv->mutex);
317+
memset(walrcv->conninfo,0,MAXCONNINFO);
318+
if (tmp_conninfo)
319+
{
320+
strlcpy((char*)walrcv->conninfo,tmp_conninfo,MAXCONNINFO);
321+
pfree(tmp_conninfo);
322+
}
323+
walrcv->ready_to_display= true;
324+
SpinLockRelease(&walrcv->mutex);
325+
307326
first_stream= true;
308327
for (;;)
309328
{
@@ -1308,10 +1327,9 @@ WalRcvGetStateString(WalRcvState state)
13081327
Datum
13091328
pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
13101329
{
1311-
#definePG_STAT_GET_WAL_RECEIVER_COLS11
13121330
TupleDesctupdesc;
1313-
Datumvalues[PG_STAT_GET_WAL_RECEIVER_COLS];
1314-
boolnulls[PG_STAT_GET_WAL_RECEIVER_COLS];
1331+
Datum*values;
1332+
bool*nulls;
13151333
WalRcvData*walrcv=WalRcv;
13161334
WalRcvStatestate;
13171335
XLogRecPtrreceive_start_lsn;
@@ -1323,41 +1341,33 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
13231341
XLogRecPtrlatest_end_lsn;
13241342
TimestampTzlatest_end_time;
13251343
char*slotname;
1344+
char*conninfo;
13261345

13271346
/* No WAL receiver, just return a tuple with NULL values */
13281347
if (walrcv->pid==0)
13291348
PG_RETURN_NULL();
13301349

1331-
/* Initialise values and NULL flags arrays */
1332-
MemSet(values,0,sizeof(values));
1333-
MemSet(nulls,0,sizeof(nulls));
1334-
1335-
/* Initialise attributes information in the tuple descriptor */
1336-
tupdesc=CreateTemplateTupleDesc(PG_STAT_GET_WAL_RECEIVER_COLS, false);
1337-
TupleDescInitEntry(tupdesc, (AttrNumber)1,"pid",
1338-
INT4OID,-1,0);
1339-
TupleDescInitEntry(tupdesc, (AttrNumber)2,"status",
1340-
TEXTOID,-1,0);
1341-
TupleDescInitEntry(tupdesc, (AttrNumber)3,"receive_start_lsn",
1342-
LSNOID,-1,0);
1343-
TupleDescInitEntry(tupdesc, (AttrNumber)4,"receive_start_tli",
1344-
INT4OID,-1,0);
1345-
TupleDescInitEntry(tupdesc, (AttrNumber)5,"received_lsn",
1346-
LSNOID,-1,0);
1347-
TupleDescInitEntry(tupdesc, (AttrNumber)6,"received_tli",
1348-
INT4OID,-1,0);
1349-
TupleDescInitEntry(tupdesc, (AttrNumber)7,"last_msg_send_time",
1350-
TIMESTAMPTZOID,-1,0);
1351-
TupleDescInitEntry(tupdesc, (AttrNumber)8,"last_msg_receipt_time",
1352-
TIMESTAMPTZOID,-1,0);
1353-
TupleDescInitEntry(tupdesc, (AttrNumber)9,"latest_end_lsn",
1354-
LSNOID,-1,0);
1355-
TupleDescInitEntry(tupdesc, (AttrNumber)10,"latest_end_time",
1356-
TIMESTAMPTZOID,-1,0);
1357-
TupleDescInitEntry(tupdesc, (AttrNumber)11,"slot_name",
1358-
TEXTOID,-1,0);
1359-
1360-
BlessTupleDesc(tupdesc);
1350+
/*
1351+
* Users attempting to read this data mustn't be shown security sensitive
1352+
* data, so sleep until everything has been properly obfuscated.
1353+
*/
1354+
retry:
1355+
SpinLockAcquire(&walrcv->mutex);
1356+
if (!walrcv->ready_to_display)
1357+
{
1358+
SpinLockRelease(&walrcv->mutex);
1359+
CHECK_FOR_INTERRUPTS();
1360+
pg_usleep(1000);
1361+
gotoretry;
1362+
}
1363+
SpinLockRelease(&walrcv->mutex);
1364+
1365+
/* determine result type */
1366+
if (get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_COMPOSITE)
1367+
elog(ERROR,"return type must be a row type");
1368+
1369+
values=palloc0(sizeof(Datum)*tupdesc->natts);
1370+
nulls=palloc0(sizeof(bool)*tupdesc->natts);
13611371

13621372
/* Take a lock to ensure value consistency */
13631373
SpinLockAcquire(&walrcv->mutex);
@@ -1371,6 +1381,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
13711381
latest_end_lsn=walrcv->latestWalEnd;
13721382
latest_end_time=walrcv->latestWalEndTime;
13731383
slotname=pstrdup(walrcv->slotname);
1384+
conninfo=pstrdup(walrcv->conninfo);
13741385
SpinLockRelease(&walrcv->mutex);
13751386

13761387
/* Fetch values */
@@ -1382,7 +1393,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
13821393
* Only superusers can see details. Other users only get the pid value
13831394
* to know whether it is a WAL receiver, but no details.
13841395
*/
1385-
MemSet(&nulls[1], true,PG_STAT_GET_WAL_RECEIVER_COLS-1);
1396+
MemSet(&nulls[1], true,sizeof(bool)* (tupdesc->natts-1));
13861397
}
13871398
else
13881399
{
@@ -1418,6 +1429,10 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
14181429
nulls[10]= true;
14191430
else
14201431
values[10]=CStringGetTextDatum(slotname);
1432+
if (*conninfo=='\0')
1433+
nulls[11]= true;
1434+
else
1435+
values[11]=CStringGetTextDatum(conninfo);
14211436
}
14221437

14231438
/* Returns the record as Datum */

‎src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/*yyyymmddN */
56-
#defineCATALOG_VERSION_NO201606261
56+
#defineCATALOG_VERSION_NO201606291
5757

5858
#endif

‎src/include/catalog/pg_proc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2746,7 +2746,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
27462746
DESCR("statistics: information about progress of backends running maintenance command");
27472747
DATA(insert OID = 3099 ( pg_stat_get_wal_sendersPGNSP PGUID 12 1 10 0 0 f f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,23,25}" "{o,o,o,o,o,o,o,o}" "{pid,state,sent_location,write_location,flush_location,replay_location,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
27482748
DESCR("statistics: information about currently active replication");
2749-
DATA(insert OID = 3317 ( pg_stat_get_wal_receiverPGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
2749+
DATA(insert OID = 3317 ( pg_stat_get_wal_receiverPGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conn_info}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
27502750
DESCR("statistics: information about WAL receiver");
27512751
DATA(insert OID = 2026 ( pg_backend_pidPGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_backend_pid _null_ _null_ _null_ ));
27522752
DESCR("statistics: current backend PID");

‎src/include/replication/walreceiver.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ typedef struct
100100
TimestampTzlatestWalEndTime;
101101

102102
/*
103-
* connection string; is used for walreceiver to connect with the primary.
103+
* connection string; initially set to connect to the primary, and later
104+
* clobbered to hide security-sensitive fields.
104105
*/
105106
charconninfo[MAXCONNINFO];
106107

@@ -118,6 +119,9 @@ typedef struct
118119
*/
119120
boolforce_reply;
120121

122+
/* set true once conninfo is ready to display (obfuscated pwds etc) */
123+
boolready_to_display;
124+
121125
/*
122126
* Latch used by startup process to wake up walreceiver after telling it
123127
* where to start streaming (after setting receiveStart and
@@ -133,6 +137,9 @@ extern WalRcvData *WalRcv;
133137
typedefvoid (*walrcv_connect_type) (char*conninfo);
134138
externPGDLLIMPORTwalrcv_connect_typewalrcv_connect;
135139

140+
typedefchar*(*walrcv_get_conninfo_type) (void);
141+
externPGDLLIMPORTwalrcv_get_conninfo_typewalrcv_get_conninfo;
142+
136143
typedefvoid (*walrcv_identify_system_type) (TimeLineID*primary_tli);
137144
externPGDLLIMPORTwalrcv_identify_system_typewalrcv_identify_system;
138145

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp