From bd58d9d883111ee84de4af480ebb018fe9b0bf27 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 4 Mar 2011 11:38:45 -0500
Subject: [PATCH] In initialize_SSL, don't fail unnecessarily when home dir is
 unavailable.

Instead, just act as though the certificate file(s) are not present.
There is only one case where this need be a hard failure condition: when
sslmode is verify-ca or verify-full, not having a root cert file is an
error.  Change the logic so that we complain only in that case, and
otherwise fall through cleanly.  This is how it used to behave pre-9.0,
but my patch 4ed4b6c54e5fab24ab2624d80e26f7546edc88ad of 2010-05-26 broke
the case.  Per report from Christian Kastner.
---
 src/interfaces/libpq/fe-secure.c | 64 ++++++++++++++++++++------------
 1 file changed, 41 insertions(+), 23 deletions(-)

diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index 8f5ba529fcc..2b7b0341cd0 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -825,37 +825,37 @@ initialize_SSL(PGconn *conn)
 	char		homedir[MAXPGPATH];
 	char		fnbuf[MAXPGPATH];
 	char		sebuf[256];
+	bool		have_homedir;
 	bool		have_cert;
 	EVP_PKEY   *pkey = NULL;
 
 	/*
 	 * We'll need the home directory if any of the relevant parameters are
-	 * defaulted.
+	 * defaulted.  If pqGetHomeDirectory fails, act as though none of the
+	 * files could be found.
 	 */
 	if (!(conn->sslcert && strlen(conn->sslcert) > 0) ||
 		!(conn->sslkey && strlen(conn->sslkey) > 0) ||
 		!(conn->sslrootcert && strlen(conn->sslrootcert) > 0) ||
 		!(conn->sslcrl && strlen(conn->sslcrl) > 0))
-	{
-		if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
-		{
-			printfPQExpBuffer(&conn->errorMessage,
-							  libpq_gettext("could not get home directory to locate client certificate files\n"));
-			return -1;
-		}
-	}
-	else
-	{
-		homedir[0] = '\0';
-	}
+		have_homedir = pqGetHomeDirectory(homedir, sizeof(homedir));
+	else						/* won't need it */
+		have_homedir = false;
 
 	/* Read the client certificate file */
 	if (conn->sslcert && strlen(conn->sslcert) > 0)
 		strncpy(fnbuf, conn->sslcert, sizeof(fnbuf));
-	else
+	else if (have_homedir)
 		snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
+	else
+		fnbuf[0] = '\0';
 
-	if (stat(fnbuf, &buf) != 0)
+	if (fnbuf[0] == '\0')
+	{
+		/* no home directory, proceed without a client cert */
+		have_cert = false;
+	}
+	else if (stat(fnbuf, &buf) != 0)
 	{
 		/*
 		 * If file is not present, just go on without a client cert; server
@@ -1001,11 +1001,13 @@ initialize_SSL(PGconn *conn)
 			strncpy(fnbuf, conn->sslkey, sizeof(fnbuf));
 		}
 	}
-	else
+	else if (have_homedir)
 	{
 		/* No PGSSLKEY specified, load default file */
 		snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE);
 	}
+	else
+		fnbuf[0] = '\0';
 
 	if (have_cert && fnbuf[0] != '\0')
 	{
@@ -1060,10 +1062,13 @@ initialize_SSL(PGconn *conn)
 	 */
 	if (conn->sslrootcert && strlen(conn->sslrootcert) > 0)
 		strncpy(fnbuf, conn->sslrootcert, sizeof(fnbuf));
-	else
+	else if (have_homedir)
 		snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CERT_FILE);
+	else
+		fnbuf[0] = '\0';
 
-	if (stat(fnbuf, &buf) == 0)
+	if (fnbuf[0] != '\0' &&
+		stat(fnbuf, &buf) == 0)
 	{
 		X509_STORE *cvstore;
 
@@ -1082,11 +1087,14 @@ initialize_SSL(PGconn *conn)
 		{
 			if (conn->sslcrl && strlen(conn->sslcrl) > 0)
 				strncpy(fnbuf, conn->sslcrl, sizeof(fnbuf));
-			else
+			else if (have_homedir)
 				snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CRL_FILE);
+			else
+				fnbuf[0] = '\0';
 
 			/* Set the flags to check against the complete CRL chain */
-			if (X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1)
+			if (fnbuf[0] != '\0' &&
+				X509_STORE_load_locations(cvstore, fnbuf, NULL) == 1)
 			{
 				/* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */
 #ifdef X509_V_FLAG_CRL_CHECK
@@ -1116,9 +1124,19 @@ initialize_SSL(PGconn *conn)
 		 */
 		if (conn->sslmode[0] == 'v')	/* "verify-ca" or "verify-full" */
 		{
-			printfPQExpBuffer(&conn->errorMessage,
-				libpq_gettext("root certificate file \"%s\" does not exist\n"
-							  "Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf);
+			/*
+			 * The only way to reach here with an empty filename is if
+			 * pqGetHomeDirectory failed.  That's a sufficiently unusual case
+			 * that it seems worth having a specialized error message for it.
+			 */
+			if (fnbuf[0] == '\0')
+				printfPQExpBuffer(&conn->errorMessage,
+								  libpq_gettext("could not get home directory to locate root certificate file\n"
+												"Either provide the file or change sslmode to disable server certificate verification.\n"));
+			else
+				printfPQExpBuffer(&conn->errorMessage,
+								  libpq_gettext("root certificate file \"%s\" does not exist\n"
+												"Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf);
 			return -1;
 		}
 	}
-- 
GitLab