diff --git a/configure b/configure index f82192ae56..59327b959d 100755 --- a/configure +++ b/configure @@ -6558,6 +6558,7 @@ fi fi if test "$with_openssl" = yes ; then + if test "$PORTNAME" != "win32"; then echo "$as_me:$LINENO: checking for CRYPTO_new_ex_data in -lcrypto" >&5 echo $ECHO_N "checking for CRYPTO_new_ex_data in -lcrypto... $ECHO_C" >&6 @@ -6696,6 +6697,146 @@ echo "$as_me: error: library 'ssl' is required for OpenSSL" >&2;} { (exit 1); exit 1; }; } fi + else + +echo "$as_me:$LINENO: checking for CRYPTO_new_ex_data in -leay32" >&5 +echo $ECHO_N "checking for CRYPTO_new_ex_data in -leay32... $ECHO_C" >&6 +if test "${ac_cv_lib_eay32_CRYPTO_new_ex_data+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-leay32 $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char CRYPTO_new_ex_data (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +CRYPTO_new_ex_data (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_eay32_CRYPTO_new_ex_data=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_eay32_CRYPTO_new_ex_data=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_eay32_CRYPTO_new_ex_data" >&5 +echo "${ECHO_T}$ac_cv_lib_eay32_CRYPTO_new_ex_data" >&6 +if test $ac_cv_lib_eay32_CRYPTO_new_ex_data = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBEAY32 1 +_ACEOF + + LIBS="-leay32 $LIBS" + +else + { { echo "$as_me:$LINENO: error: library 'eay32' is required for OpenSSL" >&5 +echo "$as_me: error: library 'eay32' is required for OpenSSL" >&2;} + { (exit 1); exit 1; }; } +fi + + +echo "$as_me:$LINENO: checking for SSL_library_init in -lssleay32" >&5 +echo $ECHO_N "checking for SSL_library_init in -lssleay32... $ECHO_C" >&6 +if test "${ac_cv_lib_ssleay32_SSL_library_init+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lssleay32 $LIBS" +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char SSL_library_init (); +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +SSL_library_init (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ssleay32_SSL_library_init=yes +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +ac_cv_lib_ssleay32_SSL_library_init=no +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_ssleay32_SSL_library_init" >&5 +echo "${ECHO_T}$ac_cv_lib_ssleay32_SSL_library_init" >&6 +if test $ac_cv_lib_ssleay32_SSL_library_init = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSSLEAY32 1 +_ACEOF + + LIBS="-lssleay32 $LIBS" + +else + { { echo "$as_me:$LINENO: error: library 'ssleay32' is required for OpenSSL" >&5 +echo "$as_me: error: library 'ssleay32' is required for OpenSSL" >&2;} + { (exit 1); exit 1; }; } +fi + + fi fi if test "$with_pam" = yes ; then diff --git a/configure.in b/configure.in index 56119d74d8..bc4976f52d 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ dnl Process this file with autoconf to produce a configure script. -dnl $PostgreSQL: pgsql/configure.in,v 1.379 2004/10/01 02:00:41 neilc Exp $ +dnl $PostgreSQL: pgsql/configure.in,v 1.380 2004/10/06 09:35:19 momjian Exp $ dnl dnl Developers, please strive to achieve this order: dnl @@ -672,8 +672,13 @@ fi if test "$with_openssl" = yes ; then dnl Order matters! - AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, [], [AC_MSG_ERROR([library 'crypto' is required for OpenSSL])]) - AC_CHECK_LIB(ssl, SSL_library_init, [], [AC_MSG_ERROR([library 'ssl' is required for OpenSSL])]) + if test "$PORTNAME" != "win32"; then + AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, [], [AC_MSG_ERROR([library 'crypto' is required for OpenSSL])]) + AC_CHECK_LIB(ssl, SSL_library_init, [], [AC_MSG_ERROR([library 'ssl' is required for OpenSSL])]) + else + AC_CHECK_LIB(eay32, CRYPTO_new_ex_data, [], [AC_MSG_ERROR([library 'eay32' is required for OpenSSL])]) + AC_CHECK_LIB(ssleay32, SSL_library_init, [], [AC_MSG_ERROR([library 'ssleay32' is required for OpenSSL])]) + fi fi if test "$with_pam" = yes ; then diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c index eee9ad2836..efe7d7c118 100644 --- a/src/backend/libpq/be-secure.c +++ b/src/backend/libpq/be-secure.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.51 2004/09/26 22:51:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.52 2004/10/06 09:35:20 momjian Exp $ * * Since the server static private key ($DataDir/server.key) * will normally be stored unencrypted so that the database @@ -268,6 +268,11 @@ rloop: break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: +#ifdef WIN32 + pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl), + (err==SSL_ERROR_WANT_READ) ? + FD_READ|FD_CLOSE : FD_WRITE|FD_CLOSE); +#endif goto rloop; case SSL_ERROR_SYSCALL: if (n == -1) @@ -356,6 +361,11 @@ wloop: break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: +#ifdef WIN32 + pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl), + (err==SSL_ERROR_WANT_READ) ? + FD_READ|FD_CLOSE : FD_WRITE|FD_CLOSE); +#endif goto wloop; case SSL_ERROR_SYSCALL: if (n == -1) @@ -717,6 +727,38 @@ initialize_SSL(void) return 0; } +#ifdef WIN32 +/* + * Win32 socket code uses nonblocking sockets. We ned to deal with that + * by waiting on the socket if the SSL accept operation didn't complete + * right away. + */ +static int pgwin32_SSL_accept(SSL *ssl) +{ + int r; + + while (1) + { + int rc; + int waitfor; + + printf("uhh\n");fflush(stdout); + r = SSL_accept(ssl); + if (r == 1) + return 1; + + rc = SSL_get_error(ssl, r); + if (rc != SSL_ERROR_WANT_READ && rc != SSL_ERROR_WANT_WRITE) + return r; + + waitfor = (rc == SSL_ERROR_WANT_READ)?FD_READ|FD_CLOSE|FD_ACCEPT:FD_WRITE|FD_CLOSE; + if (pgwin32_waitforsinglesocket(SSL_get_fd(ssl), waitfor) == 0) + return -1; + } +} +#define SSL_accept(ssl) pgwin32_SSL_accept(ssl) +#endif + /* * Destroy global SSL context. */ @@ -736,12 +778,11 @@ destroy_SSL(void) static int open_server_SSL(Port *port) { + int r; Assert(!port->ssl); Assert(!port->peer); - if (!(port->ssl = SSL_new(SSL_context)) || - !SSL_set_fd(port->ssl, port->sock) || - SSL_accept(port->ssl) <= 0) + if (!(port->ssl = SSL_new(SSL_context))) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), @@ -750,6 +791,25 @@ open_server_SSL(Port *port) close_SSL(port); return -1; } + if (!SSL_set_fd(port->ssl, port->sock)) + { + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not set SSL socket: %s", + SSLerrmessage()))); + close_SSL(port); + return -1; + } + if ((r=SSL_accept(port->ssl)) <= 0) + { + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not accept SSL connection: %i", + SSL_get_error(port->ssl,r)))); + close_SSL(port); + return -1; + } + port->count = 0; /* get client certificate, if available. */ diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/socket.c index 9be5a7ae13..de8376201f 100644 --- a/src/backend/port/win32/socket.c +++ b/src/backend/port/win32/socket.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.6 2004/09/07 14:31:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.7 2004/10/06 09:35:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -102,7 +102,7 @@ pgwin32_poll_signals(void) return 0; } -static int +int pgwin32_waitforsinglesocket(SOCKET s, int what) { static HANDLE waitevent = INVALID_HANDLE_VALUE; diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index c329c12d25..34d71483ef 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.425 2004/09/09 00:59:33 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.426 2004/10/06 09:35:21 momjian Exp $ * * NOTES * @@ -2981,6 +2981,16 @@ SubPostmasterMain(int argc, char *argv[]) /* Attach process to shared segments */ CreateSharedMemoryAndSemaphores(false, MaxBackends, 0); +#ifdef USE_SSL + /* + * Need to reinitialize the SSL library in the backend, + * since the context structures contain function pointers + * and cannot be passed through the parameter file. + */ + if (EnableSSL) + secure_initialize(); +#endif + Assert(argc == 3); /* shouldn't be any more args */ proc_exit(BackendRun(&port)); } diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 2fb4adf8fb..600f4229f0 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -227,6 +227,9 @@ /* Define to 1 if you have the `dld' library (-ldld). */ #undef HAVE_LIBDLD +/* Define to 1 if you have the `eay32' library (-leay32). */ +#undef HAVE_LIBEAY32 + /* Define to 1 if you have the `gen' library (-lgen). */ #undef HAVE_LIBGEN @@ -266,6 +269,9 @@ /* Define to 1 if you have the `ssl' library (-lssl). */ #undef HAVE_LIBSSL +/* Define to 1 if you have the `ssleay32' library (-lssleay32). */ +#undef HAVE_LIBSSLEAY32 + /* Define to 1 if you have the `unix' library (-lunix). */ #undef HAVE_LIBUNIX diff --git a/src/include/port/win32.h b/src/include/port/win32.h index 1b79271719..d3ca1f20d8 100644 --- a/src/include/port/win32.h +++ b/src/include/port/win32.h @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.36 2004/10/05 14:27:07 momjian Exp $ */ +/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.37 2004/10/06 09:35:23 momjian Exp $ */ /* undefine and redefine after #include */ #undef mkdir @@ -141,6 +141,7 @@ int pgwin32_recv(SOCKET s, char *buf, int len, int flags); int pgwin32_send(SOCKET s, char *buf, int len, int flags); const char *pgwin32_socket_strerror(int err); +int pgwin32_waitforsinglesocket(SOCKET s, int what); /* in backend/port/win32/security.c */ extern int pgwin32_is_admin(void);