*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.94 2007/02/16 17:07:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.95 2007/10/01 20:30:06 mha Exp $
*
* NOTES
* [ Most of these notes are wrong/obsolete, but perhaps not all ]
#ifdef USE_SSL
#include <openssl/ssl.h>
+#include <openssl/bio.h>
#if (SSLEAY_VERSION_NUMBER >= 0x00907000L)
#include <openssl/conf.h>
#endif
* 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
struct stat buf2;
#endif
char fnbuf[MAXPGPATH];
- FILE *fp;
- PGconn *conn = (PGconn *) SSL_get_app_data(ssl);
+ FILE *fp;
+ BIO *bio;
+ PGconn *conn = (PGconn *) SSL_get_app_data(ssl);
char sebuf[256];
if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
return 0;
}
+ /* save OpenSSL error stack */
+ ERR_set_mark();
+
/* read the user certificate */
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
- if ((fp = fopen(fnbuf, "r")) == NULL)
+ 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_X509(fp, x509, NULL, NULL) == NULL)
+
+ if (PEM_read_bio_X509(bio, x509, NULL, NULL) == NULL)
{
char *err = SSLerrmessage();
libpq_gettext("could not read certificate file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
- fclose(fp);
+ BIO_free(bio);
+ ERR_pop_to_mark();
return 0;
}
- fclose(fp);
+
+ BIO_free(bio);
#if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
if (getenv("PGSSLKEY"))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid value of PGSSLKEY environment variable\n"));
+ ERR_pop_to_mark();
return 0;
}
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);
engine_colon + 1, engine_str, err);
SSLerrfree(err);
free(engine_str);
+ ERR_pop_to_mark();
return 0;
- }
+ }
free(engine_str);
}
else
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("certificate present, but not private key file \"%s\"\n"),
fnbuf);
+ ERR_pop_to_mark();
return 0;
}
#ifndef WIN32
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("private key file \"%s\" has wrong permissions\n"),
fnbuf);
+ ERR_pop_to_mark();
return 0;
}
#endif
- if ((fp = fopen(fnbuf, "r")) == NULL)
+
+ 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_PrivateKey(fp, pkey, NULL, NULL) == NULL)
+
+ if (PEM_read_bio_PrivateKey(bio, pkey, NULL, NULL) == NULL)
{
char *err = SSLerrmessage();
libpq_gettext("could not read private key file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
- fclose(fp);
+
+ BIO_free(bio);
+ ERR_pop_to_mark();
return 0;
}
- fclose(fp);
+
+ BIO_free(bio);
}
/* verify that the cert and key go together */
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;
}