Skip to content

Commit 7e42798

Browse files
Merge pull request #9594 from ThomasWaldmann/fix/borgfs-fstab-home-dir-3395-master
helpers: get_base_dir: avoid using HOME when it incorrectly points to root's home for non-root users (fstab borgfs), fixes #3395
2 parents c409e76 + a71a252 commit 7e42798

1 file changed

Lines changed: 62 additions & 14 deletions

File tree

‎src/borg/helpers/fs.py‎

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111

1212
import platformdirs
1313

14+
try:
15+
import pwd # POSIX only
16+
except ImportError:
17+
pwd = None # win32?
18+
1419
from .errors import Error
1520

1621
from .process import prepare_subprocess_env
@@ -48,24 +53,67 @@ def ensure_dir(path, mode=stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO, pretty_dea
4853
def get_base_dir(*, legacy=False):
4954
"""Get home directory / base directory for Borg:
5055
51-
- BORG_BASE_DIR, if set
52-
- HOME, if set
53-
- ~$USER, if USER is set
54-
- ~
56+
Legacy:
57+
58+
Preference order (while being robust against misleading environment when invoked via mount helpers):
59+
60+
- BORG_BASE_DIR, if set.
61+
- HOME, if it refers to the current (effective) user's home.
62+
- ~$USER, if USER is set.
63+
- The home directory of the current (effective) user from the password database (POSIX).
64+
- ~ (platform default expansion).
65+
66+
Not legacy:
67+
68+
Just return BORG_BASE_DIR.
5569
"""
5670
if legacy:
57-
base_dir = os.environ.get("BORG_BASE_DIR") or os.environ.get("HOME")
58-
# Path.expanduser() behaves differently for '~' and '~someuser' as
59-
# parameters: when called with an explicit username, the possibly set
60-
# environment variable HOME is no longer respected. So we have to check if
61-
# it is set and only expand the user's home directory if HOME is unset.
62-
if not base_dir:
63-
base_dir = str(Path(f"~{os.environ.get('USER', '')}").expanduser())
71+
# 1. Explicit override always wins.
72+
base_dir = os.environ.get("BORG_BASE_DIR")
73+
if base_dir:
74+
return base_dir
75+
76+
# 2. Prefer HOME, but be robust against mount helpers that set HOME to root's home for non-root users.
77+
home_env = os.environ.get("HOME")
78+
if home_env and pwd is not None: # POSIX only
79+
try:
80+
# If HOME points to root's home but we are not root, prefer the invoking user's home.
81+
root_home = pwd.getpwuid(0).pw_dir
82+
uid = getattr(os, "geteuid", os.getuid)()
83+
if uid != 0 and os.path.abspath(home_env) == os.path.abspath(root_home):
84+
try:
85+
user_home = pwd.getpwuid(uid).pw_dir
86+
except Exception:
87+
user_home = None
88+
if user_home:
89+
return user_home
90+
# if we couldn't figure out the user's home, ignore HOME and continue with fallbacks
91+
home_env = None
92+
except Exception: # nosec B110
93+
# If anything goes wrong determining root's home, keep HOME as-is.
94+
pass
95+
96+
if home_env:
97+
return home_env
98+
99+
# 3. Fall back to ~$USER if set (keeps previous behavior and existing tests).
100+
user = os.environ.get("USER")
101+
if user:
102+
return os.path.expanduser("~%s" % user)
103+
104+
# 4. POSIX: use pw_home for the current uid; otherwise finally fallback to ~.
105+
if pwd is not None:
106+
try:
107+
uid = getattr(os, "geteuid", os.getuid)()
108+
return pwd.getpwuid(uid).pw_dir
109+
except Exception: # nosec B110
110+
pass
111+
112+
return os.path.expanduser("~")
64113
else:
65114
# we only care for BORG_BASE_DIR here, as it can be used to override the base dir
66-
# and not use any more or less platform specific way to determine the base dir.
67-
base_dir = os.environ.get("BORG_BASE_DIR")
68-
return base_dir
115+
# and not use any more or less platform-specific way to determine the base dir.
116+
return os.environ.get("BORG_BASE_DIR")
69117

70118

71119
def join_base_dir(*paths, **kw):

0 commit comments

Comments
 (0)