mirror of
https://github.com/postgres/postgres.git
synced 2025-12-04 12:02:48 +03:00
Add system view pg_stat_ssl
This view shows information about all connections, such as if the connection is using SSL, which cipher is used, and which client certificate (if any) is used. Reviews by Alex Shulgin, Heikki Linnakangas, Andres Freund & Michael Paquier
This commit is contained in:
@@ -646,6 +646,17 @@ CREATE VIEW pg_stat_replication AS
|
||||
WHERE S.usesysid = U.oid AND
|
||||
S.pid = W.pid;
|
||||
|
||||
CREATE VIEW pg_stat_ssl AS
|
||||
SELECT
|
||||
S.pid,
|
||||
S.ssl,
|
||||
S.sslversion AS version,
|
||||
S.sslcipher AS cipher,
|
||||
S.sslbits AS bits,
|
||||
S.sslcompression AS compression,
|
||||
S.sslclientdn AS clientdn
|
||||
FROM pg_stat_get_activity(NULL) AS S;
|
||||
|
||||
CREATE VIEW pg_replication_slots AS
|
||||
SELECT
|
||||
L.slot_name,
|
||||
|
||||
@@ -90,6 +90,8 @@ static void info_cb(const SSL *ssl, int type, int args);
|
||||
static void initialize_ecdh(void);
|
||||
static const char *SSLerrmessage(void);
|
||||
|
||||
static char *X509_NAME_to_cstring(X509_NAME *name);
|
||||
|
||||
/* are we in the middle of a renegotiation? */
|
||||
static bool in_ssl_renegotiation = false;
|
||||
|
||||
@@ -1040,3 +1042,105 @@ SSLerrmessage(void)
|
||||
snprintf(errbuf, sizeof(errbuf), _("SSL error code %lu"), errcode);
|
||||
return errbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return information about the SSL connection
|
||||
*/
|
||||
int
|
||||
be_tls_get_cipher_bits(Port *port)
|
||||
{
|
||||
int bits;
|
||||
|
||||
if (port->ssl)
|
||||
{
|
||||
SSL_get_cipher_bits(port->ssl, &bits);
|
||||
return bits;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
be_tls_get_compression(Port *port)
|
||||
{
|
||||
if (port->ssl)
|
||||
return (SSL_get_current_compression(port->ssl) != NULL);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
be_tls_get_version(Port *port, char *ptr, size_t len)
|
||||
{
|
||||
if (port->ssl)
|
||||
strlcpy(ptr, SSL_get_version(port->ssl), len);
|
||||
else
|
||||
ptr[0] = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
be_tls_get_cipher(Port *port, char *ptr, size_t len)
|
||||
{
|
||||
if (port->ssl)
|
||||
strlcpy(ptr, SSL_get_cipher(port->ssl), len);
|
||||
else
|
||||
ptr[0] = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
be_tls_get_peerdn_name(Port *port, char *ptr, size_t len)
|
||||
{
|
||||
if (port->peer)
|
||||
strlcpy(ptr, X509_NAME_to_cstring(X509_get_subject_name(port->peer)), len);
|
||||
else
|
||||
ptr[0] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an X509 subject name to a cstring.
|
||||
*
|
||||
*/
|
||||
static char *
|
||||
X509_NAME_to_cstring(X509_NAME *name)
|
||||
{
|
||||
BIO *membuf = BIO_new(BIO_s_mem());
|
||||
int i,
|
||||
nid,
|
||||
count = X509_NAME_entry_count(name);
|
||||
X509_NAME_ENTRY *e;
|
||||
ASN1_STRING *v;
|
||||
const char *field_name;
|
||||
size_t size;
|
||||
char nullterm;
|
||||
char *sp;
|
||||
char *dp;
|
||||
char *result;
|
||||
|
||||
(void) BIO_set_close(membuf, BIO_CLOSE);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
e = X509_NAME_get_entry(name, i);
|
||||
nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(e));
|
||||
v = X509_NAME_ENTRY_get_data(e);
|
||||
field_name = OBJ_nid2sn(nid);
|
||||
if (!field_name)
|
||||
field_name = OBJ_nid2ln(nid);
|
||||
BIO_printf(membuf, "/%s=", field_name);
|
||||
ASN1_STRING_print_ex(membuf, v,
|
||||
((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB)
|
||||
| ASN1_STRFLGS_UTF8_CONVERT));
|
||||
}
|
||||
|
||||
/* ensure null termination of the BIO's content */
|
||||
nullterm = '\0';
|
||||
BIO_write(membuf, &nullterm, 1);
|
||||
size = BIO_get_mem_data(membuf, &sp);
|
||||
dp = pg_any_to_server(sp, size - 1, PG_UTF8);
|
||||
|
||||
result = pstrdup(dp);
|
||||
if (dp != sp)
|
||||
pfree(dp);
|
||||
BIO_free(membuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2482,6 +2482,9 @@ static char *BackendClientHostnameBuffer = NULL;
|
||||
static char *BackendAppnameBuffer = NULL;
|
||||
static char *BackendActivityBuffer = NULL;
|
||||
static Size BackendActivityBufferSize = 0;
|
||||
#ifdef USE_SSL
|
||||
static PgBackendSSLStatus *BackendSslStatusBuffer = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ -2563,6 +2566,26 @@ CreateSharedBackendStatus(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_SSL
|
||||
/* Create or attach to the shared SSL status buffer */
|
||||
size = mul_size(sizeof(PgBackendSSLStatus), MaxBackends);
|
||||
BackendSslStatusBuffer = (PgBackendSSLStatus *)
|
||||
ShmemInitStruct("Backend SSL Status Buffer", size, &found);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
MemSet(BackendSslStatusBuffer, 0, size);
|
||||
|
||||
/* Initialize st_sslstatus pointers. */
|
||||
buffer = (char *) BackendSslStatusBuffer;
|
||||
for (i = 0; i < MaxBackends; i++)
|
||||
{
|
||||
BackendStatusArray[i].st_sslstatus = (PgBackendSSLStatus *)buffer;
|
||||
buffer += sizeof(PgBackendSSLStatus);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Create or attach to the shared activity buffer */
|
||||
BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
|
||||
MaxBackends);
|
||||
@@ -2672,6 +2695,23 @@ pgstat_bestart(void)
|
||||
NAMEDATALEN);
|
||||
else
|
||||
beentry->st_clienthostname[0] = '\0';
|
||||
#ifdef USE_SSL
|
||||
if (MyProcPort && MyProcPort->ssl != NULL)
|
||||
{
|
||||
beentry->st_ssl = true;
|
||||
beentry->st_sslstatus->ssl_bits = be_tls_get_cipher_bits(MyProcPort);
|
||||
beentry->st_sslstatus->ssl_compression = be_tls_get_compression(MyProcPort);
|
||||
be_tls_get_version(MyProcPort, beentry->st_sslstatus->ssl_version, NAMEDATALEN);
|
||||
be_tls_get_cipher(MyProcPort, beentry->st_sslstatus->ssl_cipher, NAMEDATALEN);
|
||||
be_tls_get_peerdn_name(MyProcPort, beentry->st_sslstatus->ssl_clientdn, NAMEDATALEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
beentry->st_ssl = false;
|
||||
}
|
||||
#else
|
||||
beentry->st_ssl = false;
|
||||
#endif
|
||||
beentry->st_waiting = false;
|
||||
beentry->st_state = STATE_UNDEFINED;
|
||||
beentry->st_appname[0] = '\0';
|
||||
@@ -2892,6 +2932,9 @@ pgstat_read_current_status(void)
|
||||
volatile PgBackendStatus *beentry;
|
||||
LocalPgBackendStatus *localtable;
|
||||
LocalPgBackendStatus *localentry;
|
||||
#ifdef USE_SSL
|
||||
PgBackendSSLStatus *localsslstatus;
|
||||
#endif
|
||||
char *localappname,
|
||||
*localactivity;
|
||||
int i;
|
||||
@@ -2908,6 +2951,12 @@ pgstat_read_current_status(void)
|
||||
localappname = (char *)
|
||||
MemoryContextAlloc(pgStatLocalContext,
|
||||
NAMEDATALEN * MaxBackends);
|
||||
#ifdef USE_SSL
|
||||
localsslstatus = (PgBackendSSLStatus *)
|
||||
MemoryContextAlloc(pgStatLocalContext,
|
||||
sizeof(PgBackendSSLStatus) * MaxBackends);
|
||||
#endif
|
||||
|
||||
localactivity = (char *)
|
||||
MemoryContextAlloc(pgStatLocalContext,
|
||||
pgstat_track_activity_query_size * MaxBackends);
|
||||
@@ -2944,6 +2993,14 @@ pgstat_read_current_status(void)
|
||||
localentry->backendStatus.st_appname = localappname;
|
||||
strcpy(localactivity, (char *) beentry->st_activity);
|
||||
localentry->backendStatus.st_activity = localactivity;
|
||||
localentry->backendStatus.st_ssl = beentry->st_ssl;
|
||||
#ifdef USE_SSL
|
||||
if (beentry->st_ssl)
|
||||
{
|
||||
memcpy(localsslstatus, beentry->st_sslstatus, sizeof(PgBackendSSLStatus));
|
||||
localentry->backendStatus.st_sslstatus = localsslstatus;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
pgstat_save_changecount_after(beentry, after_changecount);
|
||||
@@ -2966,6 +3023,9 @@ pgstat_read_current_status(void)
|
||||
localentry++;
|
||||
localappname += NAMEDATALEN;
|
||||
localactivity += pgstat_track_activity_query_size;
|
||||
#ifdef USE_SSL
|
||||
localsslstatus += sizeof(PgBackendSSLStatus);
|
||||
#endif
|
||||
localNumBackends++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,7 +538,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
|
||||
|
||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||
|
||||
tupdesc = CreateTemplateTupleDesc(16, false);
|
||||
tupdesc = CreateTemplateTupleDesc(22, false);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "datid",
|
||||
OIDOID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "pid",
|
||||
@@ -571,6 +571,18 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
|
||||
XIDOID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 16, "backend_xmin",
|
||||
XIDOID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 17, "ssl",
|
||||
BOOLOID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 18, "sslversion",
|
||||
TEXTOID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 19, "sslcipher",
|
||||
TEXTOID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 20, "sslbits",
|
||||
INT4OID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 21, "sslcompression",
|
||||
BOOLOID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 22, "sslclientdn",
|
||||
TEXTOID, -1, 0);
|
||||
|
||||
funcctx->tuple_desc = BlessTupleDesc(tupdesc);
|
||||
|
||||
@@ -622,8 +634,8 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
|
||||
if (funcctx->call_cntr < funcctx->max_calls)
|
||||
{
|
||||
/* for each row */
|
||||
Datum values[16];
|
||||
bool nulls[16];
|
||||
Datum values[22];
|
||||
bool nulls[22];
|
||||
HeapTuple tuple;
|
||||
LocalPgBackendStatus *local_beentry;
|
||||
PgBackendStatus *beentry;
|
||||
@@ -676,6 +688,21 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
|
||||
else
|
||||
nulls[15] = true;
|
||||
|
||||
if (beentry->st_ssl)
|
||||
{
|
||||
values[16] = BoolGetDatum(true); /* ssl */
|
||||
values[17] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
|
||||
values[18] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
|
||||
values[19] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
|
||||
values[20] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
|
||||
values[21] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
|
||||
}
|
||||
else
|
||||
{
|
||||
values[16] = BoolGetDatum(false); /* ssl */
|
||||
nulls[17] = nulls[18] = nulls[19] = nulls[20] = nulls[21] = true;
|
||||
}
|
||||
|
||||
/* Values only available to role member */
|
||||
if (has_privs_of_role(GetUserId(), beentry->st_userid))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user