From df9c435c759fffe77c9c92f70e7c095ffb6556ae Mon Sep 17 00:00:00 2001
From: Anders Kaseorg <andersk@mit.edu>
Date: Thu, 14 Oct 2021 15:20:13 -0700
Subject: [PATCH v1] Prefer getenv("HOME") to find the UNIX home directory

According to getpwnam(3):

  An application that wants to determine its user's home directory
  should inspect the value of HOME (rather than the value
  getpwuid(getuid())->pw_dir) since this allows the user to modify
  their notion of "the home directory" during a login session.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
---
 src/bin/psql/command.c            | 20 ++++++++++++--------
 src/interfaces/libpq/fe-connect.c | 14 ++++++++++----
 src/port/path.c                   | 14 ++++++++++----
 3 files changed, 32 insertions(+), 16 deletions(-)

diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 49d4c0e3ce..cc2fe6ba0e 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -15,6 +15,7 @@
 #include <sys/stat.h>			/* for stat() */
 #include <sys/time.h>			/* for setitimer() */
 #include <fcntl.h>				/* open() flags */
+#include <stdlib.h>				/* for getenv() */
 #include <unistd.h>				/* for geteuid(), getpid(), stat() */
 #else
 #include <win32.h>
@@ -558,15 +559,18 @@ exec_command_cd(PsqlScanState scan_state, bool active_branch, const char *cmd)
 			uid_t		user_id = geteuid();
 
 			errno = 0;			/* clear errno before call */
-			pw = getpwuid(user_id);
-			if (!pw)
-			{
-				pg_log_error("could not get home directory for user ID %ld: %s",
-							 (long) user_id,
-							 errno ? strerror(errno) : _("user does not exist"));
-				exit(EXIT_FAILURE);
+			dir = getenv("HOME");
+			if (dir == NULL || dir[0] == '\0') {
+				pw = getpwuid(user_id);
+				if (!pw)
+				{
+					pg_log_error("could not get home directory for user ID %ld: %s",
+								 (long) user_id,
+								 errno ? strerror(errno) : _("user does not exist"));
+					exit(EXIT_FAILURE);
+				}
+				dir = pw->pw_dir;
 			}
-			dir = pw->pw_dir;
 #else							/* WIN32 */
 
 			/*
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index b288d346f9..ebdd815c73 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -19,6 +19,7 @@
 #include <fcntl.h>
 #include <ctype.h>
 #include <time.h>
+#include <stdlib.h>
 #include <unistd.h>
 
 #include "common/ip.h"
@@ -7242,14 +7243,19 @@ bool
 pqGetHomeDirectory(char *buf, int bufsize)
 {
 #ifndef WIN32
+	const char *home;
 	char		pwdbuf[BUFSIZ];
 	struct passwd pwdstr;
 	struct passwd *pwd = NULL;
 
-	(void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
-	if (pwd == NULL)
-		return false;
-	strlcpy(buf, pwd->pw_dir, bufsize);
+	home = getenv("HOME");
+	if (home == NULL || home[0] == '\0') {
+		(void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
+		if (pwd == NULL)
+			return false;
+		home = pwd->pw_dir;
+	}
+	strlcpy(buf, home, bufsize);
 	return true;
 #else
 	char		tmppath[MAX_PATH];
diff --git a/src/port/path.c b/src/port/path.c
index c39d4688cd..607bd16c23 100644
--- a/src/port/path.c
+++ b/src/port/path.c
@@ -32,6 +32,7 @@
 #define near
 #include <shlobj.h>
 #else
+#include <stdlib.h>
 #include <unistd.h>
 #endif
 
@@ -807,14 +808,19 @@ bool
 get_home_path(char *ret_path)
 {
 #ifndef WIN32
+	const char *home;
 	char		pwdbuf[BUFSIZ];
 	struct passwd pwdstr;
 	struct passwd *pwd = NULL;
 
-	(void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
-	if (pwd == NULL)
-		return false;
-	strlcpy(ret_path, pwd->pw_dir, MAXPGPATH);
+	home = getenv("HOME");
+	if (home == NULL || home[0] == '\0') {
+		(void) pqGetpwuid(geteuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd);
+		if (pwd == NULL)
+			return false;
+		home = pwd->pw_dir;
+	}
+	strlcpy(ret_path, home, MAXPGPATH);
 	return true;
 #else
 	char	   *tmppath;
-- 
2.33.0

