diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 2c2b53911dee9216f4199eb3816bdcd2115bf971..1540ed6269356a175e24998912213096b39042ad 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.280 2009/03/28 01:36:11 momjian Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.281 2009/03/31 01:41:27 tgl Exp $ --> <chapter id="libpq"> <title><application>libpq</application> - C Library</title> @@ -63,7 +63,7 @@ The <function>PQstatus</> function should be called to check whether a connection was successfully made before queries are sent via the connection object. - + <note> <para> On Windows, there is a way to improve performance if a single @@ -6168,20 +6168,6 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) environment variables <envar>PGSSLCERT</> and <envar>PGSSLKEY</>. </para> - <para> - If your application initializes <literal>libssl</> or - <literal>libcrypto</> libraries and <application>libpq</application> - is built with <acronym>SSL</> support, you should call - <function>PQinitSSL(0)</> to tell <application>libpq</application> - that the <literal>libssl</> and <literal>libcrypto</> libraries - have been initialized by your application so - <application>libpq</application> will not initialize those libraries. - <!-- If this URL changes replace it with a URL to www.archive.org. --> - See <ulink - url="http://h71000.www7.hp.com/doc/83final/BA554_90007/ch04.html"></ulink> - for details on the SSL API. - </para> - <table id="libpq-ssl-file-usage"> <title>Libpq/Client SSL File Usage</title> <tgroup cols="3"> @@ -6225,6 +6211,93 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) </tgroup> </table> + <para> + If your application initializes <literal>libssl</> and/or + <literal>libcrypto</> libraries and <application>libpq</application> + is built with <acronym>SSL</> support, you should call + <function>PQinitOpenSSL</> to tell <application>libpq</application> + that the <literal>libssl</> and/or <literal>libcrypto</> libraries + have been initialized by your application, so that + <application>libpq</application> will not also initialize those libraries. + <!-- If this URL changes replace it with a URL to www.archive.org. --> + See <ulink + url="http://h71000.www7.hp.com/doc/83final/BA554_90007/ch04.html"></ulink> + for details on the SSL API. + </para> + + <para> + <variablelist> + <varlistentry> + <term> + <function>PQinitOpenSSL</function> + <indexterm> + <primary>PQinitOpenSSL</primary> + </indexterm> + </term> + + <listitem> + <para> + Allows applications to select which security libraries to initialize. + <synopsis> + void PQinitOpenSSL(int do_ssl, init do_crypto); + </synopsis> + </para> + + <para> + When <parameter>do_ssl</> is non-zero, <application>libpq</application> + will initialize the <application>OpenSSL</> library before first + opening a database connection. When <parameter>do_crypto</> is + non-zero, the <literal>libcrypto</> library will be initialized. By + default (if <function>PQinitOpenSSL</> is not called), both libraries + are initialized. When SSL support is not compiled in, this function is + present but does nothing. + </para> + + <para> + If your application uses and initializes either <application>OpenSSL</> + or its underlying <literal>libcrypto</> library, you <emphasis>must</> + call this function with zeroes for the appropriate parameter(s) + before first opening a database connection. Also be sure that you + have done that initialization before opening a database connection. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <function>PQinitSSL</function> + <indexterm> + <primary>PQinitSSL</primary> + </indexterm> + </term> + + <listitem> + <para> + Allows applications to select which security libraries to initialize. + <synopsis> + void PQinitSSL(int do_ssl); + </synopsis> + </para> + + <para> + This function is equivalent to + <literal>PQinitOpenSSL(do_ssl, do_ssl)</>. + It is sufficient for applications that initialize both or neither + of <application>OpenSSL</> and <literal>libcrypto</>. + </para> + + <para> + <function>PQinitSSL</> has been present since + <productname>PostgreSQL</> 8.0, while <function>PQinitOpenSSL</> + was added in <productname>PostgreSQL</> 8.4, so <function>PQinitSSL</> + might be preferable for applications that need to work with older + versions of <application>libpq</application>. + </para> + </listitem> + </varlistentry> + </variablelist> + </para> + </sect1> diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index 655968e5f32cce6eead37d0d4c039de89dd1eabb..f08fc58109e0b347eed8d14d4a5ee22b09105e4c 100644 --- a/src/interfaces/libpq/exports.txt +++ b/src/interfaces/libpq/exports.txt @@ -1,4 +1,4 @@ -# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.22 2008/09/22 13:55:14 tgl Exp $ +# $PostgreSQL: pgsql/src/interfaces/libpq/exports.txt,v 1.23 2009/03/31 01:41:27 tgl Exp $ # Functions to be exported by libpq DLLs PQconnectdb 1 PQsetdbLogin 2 @@ -152,3 +152,4 @@ PQresultInstanceData 149 PQresultSetInstanceData 150 PQfireResultCreateEvents 151 PQconninfoParse 152 +PQinitOpenSSL 153 diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index e29ee227bf9dc82ac44b2f03e2a9cd01cdcfc1f9..a876793baf436a98bdae6d77559a915f4a6bb37f 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.121 2009/03/28 18:48:55 momjian Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.122 2009/03/31 01:41:27 tgl Exp $ * * NOTES * @@ -99,10 +99,11 @@ static char *SSLerrmessage(void); static void SSLerrfree(char *buf); static bool pq_init_ssl_lib = true; +static bool pq_init_crypto_lib = true; static SSL_CTX *SSL_context = NULL; #ifdef ENABLE_THREAD_SAFETY -static int ssl_open_connections = 0; +static long ssl_open_connections = 0; #ifndef WIN32 static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -171,9 +172,29 @@ static long win32_ssl_create_mutex = 0; */ void PQinitSSL(int do_init) +{ + PQinitOpenSSL(do_init, do_init); +} + +/* + * Exported function to allow application to tell us it's already + * initialized OpenSSL and/or libcrypto. + */ +void +PQinitOpenSSL(int do_ssl, int do_crypto) { #ifdef USE_SSL - pq_init_ssl_lib = do_init; +#ifdef ENABLE_THREAD_SAFETY + /* + * Disallow changing the flags while we have open connections, else + * we'd get completely confused. + */ + if (ssl_open_connections != 0) + return; +#endif + + pq_init_ssl_lib = do_ssl; + pq_init_crypto_lib = do_crypto; #endif } @@ -810,10 +831,10 @@ pq_lockingcallback(int mode, int n, const char *file, int line) /* * Initialize SSL system. In threadsafe mode, this includes setting - * up OpenSSL callback functions to do thread locking. + * up libcrypto callback functions to do thread locking. * - * If the caller has told us (through PQinitSSL) that he's taking care - * of SSL, we expect that callbacks are already set, and won't try to + * If the caller has told us (through PQinitOpenSSL) that he's taking care + * of libcrypto, we expect that callbacks are already set, and won't try to * override it. * * The conn parameter is only used to be able to pass back an error @@ -840,11 +861,11 @@ init_ssl_system(PGconn *conn) if (pthread_mutex_lock(&ssl_config_mutex)) return -1; - if (pq_init_ssl_lib) + if (pq_init_crypto_lib) { /* - * If necessary, set up an array to hold locks for OpenSSL. OpenSSL will - * tell us how big to make this array. + * If necessary, set up an array to hold locks for libcrypto. + * libcrypto will tell us how big to make this array. */ if (pq_lockarray == NULL) { @@ -870,8 +891,7 @@ init_ssl_system(PGconn *conn) if (ssl_open_connections++ == 0) { - /* This is actually libcrypto, not libssl. */ - /* These are only required for threaded SSL applications */ + /* These are only required for threaded libcrypto applications */ CRYPTO_set_id_callback(pq_threadidcallback); CRYPTO_set_locking_callback(pq_lockingcallback); } @@ -913,9 +933,10 @@ init_ssl_system(PGconn *conn) /* * This function is needed because if the libpq library is unloaded * from the application, the callback functions will no longer exist when - * SSL used by other parts of the system. For this reason, - * we unregister the SSL callback functions when the last libpq - * connection is closed. + * libcrypto is used by other parts of the system. For this reason, + * we unregister the callback functions when the last libpq + * connection is closed. (The same would apply for OpenSSL callbacks + * if we had any.) * * Callbacks are only set when we're compiled in threadsafe mode, so * we only need to remove them in this case. @@ -928,27 +949,23 @@ destroy_ssl_system(void) if (pthread_mutex_lock(&ssl_config_mutex)) return; - if (pq_init_ssl_lib) + if (pq_init_crypto_lib && ssl_open_connections > 0) + --ssl_open_connections; + + if (pq_init_crypto_lib && ssl_open_connections == 0) { - if (ssl_open_connections > 0) - --ssl_open_connections; + /* No connections left, unregister libcrypto callbacks */ + CRYPTO_set_locking_callback(NULL); + CRYPTO_set_id_callback(NULL); - if (ssl_open_connections == 0) - { - /* This is actually libcrypto, not libssl. */ - /* No connections left, unregister all callbacks */ - CRYPTO_set_locking_callback(NULL); - CRYPTO_set_id_callback(NULL); - - /* - * We don't free the lock array. If we get another connection - * from the same caller, we will just re-use it with the existing - * mutexes. - * - * This means we leak a little memory on repeated load/unload - * of the library. - */ - } + /* + * We don't free the lock array. If we get another connection + * in this process, we will just re-use it with the existing + * mutexes. + * + * This means we leak a little memory on repeated load/unload + * of the library. + */ } pthread_mutex_unlock(&ssl_config_mutex); @@ -995,8 +1012,6 @@ initialize_SSL(PGconn *conn) homedir[0] = '\0'; } - - if (conn->sslrootcert) strncpy(fnbuf, conn->sslrootcert, sizeof(fnbuf)); else diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index df756fde21c5b0ce4fb50ca572cc3a98ab4f0416..bef0908707101f18a43e9ebd4302c4082e7d1226 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.145 2009/01/01 17:24:03 momjian Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.146 2009/03/31 01:41:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -302,6 +302,9 @@ extern void *PQgetssl(PGconn *conn); /* Tell libpq whether it needs to initialize OpenSSL */ extern void PQinitSSL(int do_init); +/* More detailed way to tell libpq whether it needs to initialize OpenSSL */ +extern void PQinitOpenSSL(int do_ssl, int do_crypto); + /* Set verbosity for PQerrorMessage and PQresultErrorMessage */ extern PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);