</entry>
</row>
+ <row>
+ <entry><structname>pg_stat_ssl</><indexterm><primary>pg_stat_ssl</primary></indexterm></entry>
+ <entry>One row per connection (regular and replication), showing information about
+ SSL used on this connection.
+ See <xref linkend="pg-stat-ssl-view"> for details.
+ </entry>
+ </row>
+
</tbody>
</tgroup>
</table>
listed; no information is available about downstream standby servers.
</para>
+ <table id="pg-stat-ssl-view" xreflabel="pg_stat_ssl">
+ <title><structname>pg_stat_ssl</structname> View</title>
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Column</entry>
+ <entry>Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><structfield>pid</></entry>
+ <entry><type>integer</></entry>
+ <entry>Process ID of a backend or WAL sender process</entry>
+ </row>
+ <row>
+ <entry><structfield>ssl</></entry>
+ <entry><type>boolean</></entry>
+ <entry>True if SSL is used on this connection</entry>
+ </row>
+ <row>
+ <entry><structfield>version</></entry>
+ <entry><type>text</></entry>
+ <entry>Version of SSL in use, or NULL if SSL is not in use
+ on this connection</entry>
+ </row>
+ <row>
+ <entry><structfield>cipher</></entry>
+ <entry><type>text</></entry>
+ <entry>Name of SSL cipher in use, or NULL if SSL is not in use
+ on this connection</entry>
+ </row>
+ <row>
+ <entry><structfield>bits</></entry>
+ <entry><type>integer</></entry>
+ <entry>Number of bits in the encryption algorithm used, or NULL
+ if SSL is not used on this connection</entry>
+ </row>
+ <row>
+ <entry><structfield>compression</></entry>
+ <entry><type>boolean</></entry>
+ <entry>True if SSL compression is in use, false if not,
+ or NULL if SSL is not in use on this connection</entry>
+ </row>
+ <row>
+ <entry><structfield>clientdn</></entry>
+ <entry><type>text</></entry>
+ <entry>Distinguished Name (DN) field from the client certificate
+ used, or NULL if no client certificate was supplied or if SSL
+ is not in use on this connection. This field is truncated if the
+ DN field is longer than <symbol>NAMEDATALEN</symbol> (64 characters
+ in a standard build)
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ The <structname>pg_stat_ssl</structname> view will contain one row per
+ backend or WAL sender process, showing statistics about SSL usage on
+ this connection. It can be joined to <structname>pg_stat_activity</structname>
+ or <structname>pg_stat_replication</structname> on the
+ <structfield>pid</structfield> column to get more details about the
+ connection.
+ </para>
+
<table id="pg-stat-archiver-view" xreflabel="pg_stat_archiver">
<title><structname>pg_stat_archiver</structname> View</title>
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,
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;
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;
+}
static char *BackendAppnameBuffer = NULL;
static char *BackendActivityBuffer = NULL;
static Size BackendActivityBufferSize = 0;
+#ifdef USE_SSL
+static PgBackendSSLStatus *BackendSslStatusBuffer = NULL;
+#endif
/*
}
}
+#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);
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';
volatile PgBackendStatus *beentry;
LocalPgBackendStatus *localtable;
LocalPgBackendStatus *localentry;
+#ifdef USE_SSL
+ PgBackendSSLStatus *localsslstatus;
+#endif
char *localappname,
*localactivity;
int i;
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);
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);
localentry++;
localappname += NAMEDATALEN;
localactivity += pgstat_track_activity_query_size;
+#ifdef USE_SSL
+ localsslstatus += sizeof(PgBackendSSLStatus);
+#endif
localNumBackends++;
}
}
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",
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);
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;
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))
{
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201504061
+#define CATALOG_VERSION_NO 201504121
#endif
DESCR("statistics: number of auto analyzes for a table");
DATA(insert OID = 1936 ( pg_stat_get_backend_idset PGNSP PGUID 12 1 100 0 0 f f f f t t s 0 0 23 "" _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
DESCR("statistics: currently active backend IDs");
-DATA(insert OID = 2022 ( pg_stat_get_activity PGNSP PGUID 12 1 100 0 0 f f f f f t s 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23,28,28}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin}" _null_ pg_stat_get_activity _null_ _null_ _null_ ));
+DATA(insert OID = 2022 ( pg_stat_get_activity PGNSP PGUID 12 1 100 0 0 f f f f f t s 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ pg_stat_get_activity _null_ _null_ _null_ ));
DESCR("statistics: information about currently active backends");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s 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_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
extern ssize_t be_tls_read(Port *port, void *ptr, size_t len, int *waitfor);
extern ssize_t be_tls_write(Port *port, void *ptr, size_t len, int *waitfor);
+extern int be_tls_get_cipher_bits(Port *port);
+extern bool be_tls_get_compression(Port *port);
+extern void be_tls_get_version(Port *port, char *ptr, size_t len);
+extern void be_tls_get_cipher(Port *port, char *ptr, size_t len);
+extern void be_tls_get_peerdn_name(Port *port, char *ptr, size_t len);
#endif
extern ProtocolVersion FrontendProtocol;
*/
+/*
+ * PgBackendSSLStatus
+ *
+ * For each backend, we keep the SSL status in a separate struct, that
+ * is only filled in if SSL is enabled.
+ */
+typedef struct PgBackendSSLStatus
+{
+ /* Information about SSL connection */
+ int ssl_bits;
+ bool ssl_compression;
+ char ssl_version[NAMEDATALEN]; /* MUST be null-terminated */
+ char ssl_cipher[NAMEDATALEN]; /* MUST be null-terminated */
+ char ssl_clientdn[NAMEDATALEN]; /* MUST be null-terminated */
+} PgBackendSSLStatus;
+
+
/* ----------
* PgBackendStatus
*
SockAddr st_clientaddr;
char *st_clienthostname; /* MUST be null-terminated */
+ /* Information about SSL connection */
+ bool st_ssl;
+ PgBackendSSLStatus *st_sslstatus;
+
/* Is backend currently waiting on an lmgr lock? */
bool st_waiting;
s.backend_xmin,
s.query
FROM pg_database d,
- pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin),
+ pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn),
pg_authid u
WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
pg_stat_all_indexes| SELECT c.oid AS relid,
w.replay_location,
w.sync_priority,
w.sync_state
- FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin),
+ FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn),
pg_authid u,
pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state)
WHERE ((s.usesysid = u.oid) AND (s.pid = w.pid));
+pg_stat_ssl| 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::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
pg_stat_sys_indexes| SELECT pg_stat_all_indexes.relid,
pg_stat_all_indexes.indexrelid,
pg_stat_all_indexes.schemaname,