On Tue, Nov 11, 2014 at 1:04 AM, Michael Paquier <michael.paqu...@gmail.com> wrote: > On Tue, Nov 11, 2014 at 1:43 AM, Magnus Hagander <mag...@hagander.net> > wrote: >> >> Right now it just truncates the dn at NAMEDATALEN - so treating it the >> same as we do with hostnames. My guess is this is not a big problem >> because in the case of long DNs, most of the time the important stuff >> is at the beginning anyway... (And it's not like it's actually used >> for authentication, in which case it would of course be a problem). > > You should add it to the next CF for proper tracking, there are already many > patches in the queue waiting for reviews :)
Absolutely - I just wanted those that were already involved in the thread to get a chance to look at it early :) didn't want to submit it until it was complete. Which it is now - attached is a new version that includes docs. -- Magnus Hagander Me: http://www.hagander.net/ Work: http://www.redpill-linpro.com/
*** a/doc/src/sgml/monitoring.sgml --- b/doc/src/sgml/monitoring.sgml *************** *** 300,305 **** postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser --- 300,313 ---- </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 statistics about + SSL used on this connection. + See <xref linkend="pg-stat-ssl-view"> for details. + </entry> + </row> + </tbody> </tgroup> </table> *************** *** 825,830 **** postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser --- 833,907 ---- 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>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>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>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> *** a/src/backend/catalog/system_views.sql --- b/src/backend/catalog/system_views.sql *************** *** 648,653 **** CREATE VIEW pg_stat_replication AS --- 648,664 ---- WHERE S.usesysid = U.oid AND S.pid = W.pid; + CREATE VIEW pg_stat_ssl AS + SELECT + I.pid, + I.ssl, + I.bits, + I.compression, + I.version, + I.cipher, + I.clientdn + FROM pg_stat_get_sslstatus() AS I; + CREATE VIEW pg_replication_slots AS SELECT L.slot_name, *** a/src/backend/libpq/be-secure-openssl.c --- b/src/backend/libpq/be-secure-openssl.c *************** *** 88,93 **** static void info_cb(const SSL *ssl, int type, int args); --- 88,95 ---- 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; *************** *** 1053,1055 **** SSLerrmessage(void) --- 1055,1159 ---- 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), NAMEDATALEN); + 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)), NAMEDATALEN); + 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; + } *** a/src/backend/postmaster/pgstat.c --- b/src/backend/postmaster/pgstat.c *************** *** 2386,2391 **** pgstat_fetch_global(void) --- 2386,2394 ---- static PgBackendStatus *BackendStatusArray = NULL; static PgBackendStatus *MyBEEntry = NULL; static char *BackendClientHostnameBuffer = NULL; + static char *BackendSslVersionBuffer = NULL; + static char *BackendSslCipherBuffer = NULL; + static char *BackendSslClientDNBuffer = NULL; static char *BackendAppnameBuffer = NULL; static char *BackendActivityBuffer = NULL; static Size BackendActivityBufferSize = 0; *************** *** 2470,2475 **** CreateSharedBackendStatus(void) --- 2473,2531 ---- } } + /* Create or attach to the shared SSL status buffers */ + size = mul_size(NAMEDATALEN, MaxBackends); + BackendSslVersionBuffer = (char *) + ShmemInitStruct("Backend SSL Version Buffer", size, &found); + + if (!found) + { + MemSet(BackendSslVersionBuffer, 0, size); + + /* Initialize st_ssl_version pointers. */ + buffer = BackendSslVersionBuffer; + for (i = 0; i < MaxBackends; i++) + { + BackendStatusArray[i].st_ssl_version = buffer; + buffer += NAMEDATALEN; + } + } + + size = mul_size(NAMEDATALEN, MaxBackends); + BackendSslCipherBuffer = (char *) + ShmemInitStruct("Backend SSL Cipher Buffer", size, &found); + + if (!found) + { + MemSet(BackendSslCipherBuffer, 0, size); + + /* Initialize st_ssl_cipher pointers. */ + buffer = BackendSslCipherBuffer; + for (i = 0; i < MaxBackends; i++) + { + BackendStatusArray[i].st_ssl_cipher = buffer; + buffer += NAMEDATALEN; + } + } + + size = mul_size(NAMEDATALEN, MaxBackends); + BackendSslClientDNBuffer = (char *) + ShmemInitStruct("Backend SSL Client DN Buffer", size, &found); + + if (!found) + { + MemSet(BackendSslClientDNBuffer, 0, size); + + /* Initialize st_ssl_clientdn pointers. */ + buffer = BackendSslClientDNBuffer; + for (i = 0; i < MaxBackends; i++) + { + BackendStatusArray[i].st_ssl_clientdn = buffer; + buffer += NAMEDATALEN; + } + } + + /* Create or attach to the shared activity buffer */ BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size, MaxBackends); *************** *** 2579,2584 **** pgstat_bestart(void) --- 2635,2653 ---- NAMEDATALEN); else beentry->st_clienthostname[0] = '\0'; + #ifdef USE_SSL + beentry->st_ssl = (MyProcPort && MyProcPort->ssl != NULL); + if (beentry->st_ssl) + { + beentry->st_ssl_bits = be_tls_get_cipher_bits(MyProcPort); + beentry->st_ssl_compression = be_tls_get_compression(MyProcPort); + be_tls_get_version(MyProcPort, beentry->st_ssl_version, NAMEDATALEN); + be_tls_get_cipher(MyProcPort, beentry->st_ssl_cipher, NAMEDATALEN); + be_tls_get_peerdn_name(MyProcPort, beentry->st_ssl_clientdn, NAMEDATALEN); + } + #else + beentry->st_ssl = false; + #endif beentry->st_waiting = false; beentry->st_state = STATE_UNDEFINED; beentry->st_appname[0] = '\0'; *************** *** 2806,2811 **** pgstat_read_current_status(void) --- 2875,2883 ---- LocalPgBackendStatus *localtable; LocalPgBackendStatus *localentry; char *localappname, + *localsslversion, + *localsslcipher, + *localsslclientdn, *localactivity; int i; *************** *** 2821,2826 **** pgstat_read_current_status(void) --- 2893,2907 ---- localappname = (char *) MemoryContextAlloc(pgStatLocalContext, NAMEDATALEN * MaxBackends); + localsslversion = (char *) + MemoryContextAlloc(pgStatLocalContext, + NAMEDATALEN * MaxBackends); + localsslcipher = (char *) + MemoryContextAlloc(pgStatLocalContext, + NAMEDATALEN * MaxBackends); + localsslclientdn = (char *) + MemoryContextAlloc(pgStatLocalContext, + NAMEDATALEN * MaxBackends); localactivity = (char *) MemoryContextAlloc(pgStatLocalContext, pgstat_track_activity_query_size * MaxBackends); *************** *** 2854,2859 **** pgstat_read_current_status(void) --- 2935,2946 ---- localentry->backendStatus.st_appname = localappname; strcpy(localactivity, (char *) beentry->st_activity); localentry->backendStatus.st_activity = localactivity; + strcpy(localsslversion, (char *) beentry->st_ssl_version); + localentry->backendStatus.st_ssl_version = localsslversion; + strcpy(localsslcipher, (char *) beentry->st_ssl_cipher); + localentry->backendStatus.st_ssl_cipher = localsslcipher; + strcpy(localsslclientdn, (char *) beentry->st_ssl_clientdn); + localentry->backendStatus.st_ssl_clientdn = localsslclientdn; } if (save_changecount == beentry->st_changecount && *************** *** 2874,2879 **** pgstat_read_current_status(void) --- 2961,2969 ---- localentry++; localappname += NAMEDATALEN; + localsslversion += NAMEDATALEN; + localsslcipher += NAMEDATALEN; + localsslclientdn += NAMEDATALEN; localactivity += pgstat_track_activity_query_size; localNumBackends++; } *** a/src/backend/utils/adt/pgstatfuncs.c --- b/src/backend/utils/adt/pgstatfuncs.c *************** *** 821,826 **** pg_stat_get_activity(PG_FUNCTION_ARGS) --- 821,905 ---- } } + /* + * Returns SSL information for all connections, both regular backend and + * WAL senders. + */ + Datum + pg_stat_get_sslstatus(PG_FUNCTION_ARGS) + { + #define PG_STAT_GET_SSLSTATUS_COLS 7 + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + MemoryContext per_query_ctx; + MemoryContext oldcontext; + int i; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not " \ + "allowed in this context"))); + + /* Build a tuple descriptor for our result type */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + elog(ERROR, "return type must be a row type"); + + per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; + oldcontext = MemoryContextSwitchTo(per_query_ctx); + + tupstore = tuplestore_begin_heap(true, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + + MemoryContextSwitchTo(oldcontext); + + for (i = 0; i < pgstat_fetch_stat_numbackends(); i++) + { + Datum values[PG_STAT_GET_SSLSTATUS_COLS]; + bool nulls[PG_STAT_GET_SSLSTATUS_COLS]; + PgBackendStatus *beentry = &pgstat_fetch_stat_local_beentry(i+1)->backendStatus; + + if (beentry->st_procpid == 0) + continue; + + MemSet(nulls, 0, sizeof(nulls)); + /* XXX: somethign superuser only? */ + + values[0] = Int32GetDatum(beentry->st_procpid); + values[1] = BoolGetDatum(beentry->st_ssl); + if (beentry->st_ssl) + { + values[2] = Int32GetDatum(beentry->st_ssl_bits); + values[3] = BoolGetDatum(beentry->st_ssl_compression); + values[4] = CStringGetTextDatum(beentry->st_ssl_version); + values[5] = CStringGetTextDatum(beentry->st_ssl_cipher); + values[6] = CStringGetTextDatum(beentry->st_ssl_clientdn); + } + else + { + nulls[2] = true; /* bits */ + nulls[3] = true; /* compression */ + nulls[4] = true; /* version */ + nulls[5] = true; /* cipher */ + nulls[6] = true; /* clientdn */ + } + + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } + + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); + + return (Datum) 0; + } Datum pg_backend_pid(PG_FUNCTION_ARGS) *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** *** 2722,2727 **** DATA(insert OID = 2022 ( pg_stat_get_activity PGNSP PGUID 12 1 100 0 0 f f f --- 2722,2729 ---- 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"); + DATA(insert OID = 3261 ( pg_stat_get_sslstatus PGNSP PGUID 12 1 10 0 0 f f f f f t s 0 0 2249 "" "{23,16,23,16,25,25,25}" "{o,o,o,o,o,o,o}" "{pid,ssl,bits,compression,version,cipher,clientdn}" _null_ pg_stat_get_sslstatus _null_ _null_ _null_ )); + DESCR("statistics: information about SSL connections"); DATA(insert OID = 2026 ( pg_backend_pid PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 23 "" _null_ _null_ _null_ _null_ pg_backend_pid _null_ _null_ _null_ )); DESCR("statistics: current backend PID"); DATA(insert OID = 1937 ( pg_stat_get_backend_pid PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 23 "23" _null_ _null_ _null_ _null_ pg_stat_get_backend_pid _null_ _null_ _null_ )); *** a/src/include/libpq/libpq-be.h --- b/src/include/libpq/libpq-be.h *************** *** 210,215 **** extern void be_tls_close(Port *port); --- 210,220 ---- extern ssize_t be_tls_read(Port *port, void *ptr, size_t len); extern ssize_t be_tls_write(Port *port, void *ptr, size_t len); + 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; *** a/src/include/pgstat.h --- b/src/include/pgstat.h *************** *** 732,737 **** typedef struct PgBackendStatus --- 732,745 ---- SockAddr st_clientaddr; char *st_clienthostname; /* MUST be null-terminated */ + /* Information about SSL connection */ + bool st_ssl; + int st_ssl_bits; + bool st_ssl_compression; + char *st_ssl_version; /* MUST be null-terminated */ + char *st_ssl_cipher; /* MUST be null-terminated */ + char *st_ssl_clientdn; /* MUST be null-terminated */ + /* Is backend currently waiting on an lmgr lock? */ bool st_waiting; *** a/src/test/regress/expected/rules.out --- b/src/test/regress/expected/rules.out *************** *** 1747,1752 **** pg_stat_replication| SELECT s.pid, --- 1747,1760 ---- 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 i.pid, + i.ssl, + i.bits, + i.compression, + i.version, + i.cipher, + i.clientdn + FROM pg_stat_get_sslstatus() i(pid, ssl, bits, compression, version, cipher, clientdn); pg_stat_sys_indexes| SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname,
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers