Index: src/interfaces/libpq/fe-secure.c =================================================================== RCS file: /cvsroot/pgsql/src/interfaces/libpq/fe-secure.c,v retrieving revision 1.94 diff -c -r1.94 fe-secure.c *** src/interfaces/libpq/fe-secure.c 16 Feb 2007 17:07:00 -0000 1.94 --- src/interfaces/libpq/fe-secure.c 1 Oct 2007 13:21:43 -0000 *************** *** 111,116 **** --- 111,117 ---- #ifdef USE_SSL #include + #include #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) #include #endif *************** *** 567,572 **** --- 568,577 ---- * This callback is only called when the server wants a * client cert. * + * Since BIO functions can set OpenSSL error codes, we must + * reset the OpenSSL error stack on *every* exit from this + * function once we've started using BIO. + * * Must return 1 on success, 0 on no data or error. */ static int *************** *** 579,586 **** struct stat buf2; #endif char fnbuf[MAXPGPATH]; ! FILE *fp; ! PGconn *conn = (PGconn *) SSL_get_app_data(ssl); char sebuf[256]; if (!pqGetHomeDirectory(homedir, sizeof(homedir))) --- 584,592 ---- struct stat buf2; #endif char fnbuf[MAXPGPATH]; ! FILE *fp; ! BIO *bio; ! PGconn *conn = (PGconn *) SSL_get_app_data(ssl); char sebuf[256]; if (!pqGetHomeDirectory(homedir, sizeof(homedir))) *************** *** 590,605 **** return 0; } /* read the user certificate */ snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE); ! if ((fp = fopen(fnbuf, "r")) == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open certificate file \"%s\": %s\n"), fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf))); return 0; } ! if (PEM_read_X509(fp, x509, NULL, NULL) == NULL) { char *err = SSLerrmessage(); --- 596,616 ---- return 0; } + /* save OpenSSL error stack */ + ERR_set_mark(); + /* read the user certificate */ snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE); ! if ((bio = BIO_new_file(fnbuf, "r")) == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open certificate file \"%s\": %s\n"), fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf))); + ERR_pop_to_mark(); return 0; } ! ! if (PEM_read_bio_X509(bio, x509, NULL, NULL) == NULL) { char *err = SSLerrmessage(); *************** *** 607,616 **** libpq_gettext("could not read certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); ! fclose(fp); return 0; } ! fclose(fp); #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE) if (getenv("PGSSLKEY")) --- 618,629 ---- libpq_gettext("could not read certificate file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); ! BIO_free(bio); ! ERR_pop_to_mark(); return 0; } ! ! BIO_free(bio); #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE) if (getenv("PGSSLKEY")) *************** *** 625,630 **** --- 638,644 ---- { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("invalid value of PGSSLKEY environment variable\n")); + ERR_pop_to_mark(); return 0; } *************** *** 640,647 **** engine_str, err); SSLerrfree(err); free(engine_str); return 0; ! } *pkey = ENGINE_load_private_key(engine_ptr, engine_colon + 1, NULL, NULL); --- 654,662 ---- engine_str, err); SSLerrfree(err); free(engine_str); + ERR_pop_to_mark(); return 0; ! } *pkey = ENGINE_load_private_key(engine_ptr, engine_colon + 1, NULL, NULL); *************** *** 654,661 **** engine_colon + 1, engine_str, err); SSLerrfree(err); free(engine_str); return 0; ! } free(engine_str); } else --- 669,677 ---- engine_colon + 1, engine_str, err); SSLerrfree(err); free(engine_str); + ERR_pop_to_mark(); return 0; ! } free(engine_str); } else *************** *** 668,673 **** --- 684,690 ---- printfPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate present, but not private key file \"%s\"\n"), fnbuf); + ERR_pop_to_mark(); return 0; } #ifndef WIN32 *************** *** 677,702 **** printfPQExpBuffer(&conn->errorMessage, libpq_gettext("private key file \"%s\" has wrong permissions\n"), fnbuf); return 0; } #endif ! if ((fp = fopen(fnbuf, "r")) == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open private key file \"%s\": %s\n"), fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf))); return 0; } #ifndef WIN32 if (fstat(fileno(fp), &buf2) == -1 || buf.st_dev != buf2.st_dev || buf.st_ino != buf2.st_ino) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("private key file \"%s\" changed during execution\n"), fnbuf); return 0; } #endif ! if (PEM_read_PrivateKey(fp, pkey, NULL, NULL) == NULL) { char *err = SSLerrmessage(); --- 694,725 ---- printfPQExpBuffer(&conn->errorMessage, libpq_gettext("private key file \"%s\" has wrong permissions\n"), fnbuf); + ERR_pop_to_mark(); return 0; } #endif ! ! if ((bio = BIO_new_file(fnbuf, "r")) == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open private key file \"%s\": %s\n"), fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf))); + ERR_pop_to_mark(); return 0; } #ifndef WIN32 + BIO_get_fp(bio, &fp); if (fstat(fileno(fp), &buf2) == -1 || buf.st_dev != buf2.st_dev || buf.st_ino != buf2.st_ino) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("private key file \"%s\" changed during execution\n"), fnbuf); + ERR_pop_to_mark(); return 0; } #endif ! ! if (PEM_read_bio_PrivateKey(bio, pkey, NULL, NULL) == NULL) { char *err = SSLerrmessage(); *************** *** 704,713 **** libpq_gettext("could not read private key file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); ! fclose(fp); return 0; } ! fclose(fp); } /* verify that the cert and key go together */ --- 727,739 ---- libpq_gettext("could not read private key file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); ! ! BIO_free(bio); ! ERR_pop_to_mark(); return 0; } ! ! BIO_free(bio); } /* verify that the cert and key go together */ *************** *** 719,727 **** --- 745,756 ---- libpq_gettext("certificate does not match private key file \"%s\": %s\n"), fnbuf, err); SSLerrfree(err); + ERR_pop_to_mark(); return 0; } + ERR_pop_to_mark(); + return 1; }