From: Anders Kaseorg <andersk@mit.edu>
To: pgsql-hackers@lists.postgresql.org <pgsql-hackers@lists.postgresql.org>
Subject: [PATCH] Prefer getenv("HOME") to find the UNIX home directory
Date: Thu, 14 Oct 2021 23:04:14 +0000
Message-ID: <1634252654444.90107@mit.edu> (raw)
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.
This is important for systems where many users share the same UID, and for test systems that change HOME to avoid interference with the user’s real home directory. It matches what most applications do, as well as what glibc does for glob("~", GLOB_TILDE, …) and wordexp("~", …).
There was some previous discussion of this in 2016, where although there were some questions about the use case, there seemed to be general support for the concept:
https://www.postgresql.org/message-id/flat/CAEH6cQqbdbXoUHJBbX9ixwfjFFsUC-a8hFntKcci%3DdiWgBb3fQ%40m...
Regardless of whether one thinks modifying HOME is a good idea, if we happen to find ourselves in that case, we should respect the modified HOME, so that when the user creates (say) a ~/.pgpass file, we’ll look for it at the same place the user’s editor created it. getenv() also skips the overhead of reading /etc/passwd as an added bonus.
The way I ran into this issue myself was in a test suite that runs on GitHub Actions, which automatically sets HOME=/github/home.
Anders
=
Attachments:v1-0001-Prefer-getenv-HOME-to-find-the-UNIX-home-director.patch (text/x-patch, 3.8K) download
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.cindex 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.cindex 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.cindex 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: andersk@mit.edu, pgsql-hackers@lists.postgresql.org
Subject: Re: [PATCH] Prefer getenv("HOME") to find the UNIX home directory
In-Reply-To: <1634252654444.90107@mit.edu>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox