https://github.com/python/cpython/commit/6e0ad71a29555f40f3bc7ff4819c727f5adf075a
commit: 6e0ad71a29555f40f3bc7ff4819c727f5adf075a
branch: 3.13
author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com>
committer: picnixz <10796600+picn...@users.noreply.github.com>
date: 2025-06-22T20:12:20Z
summary:

[3.13] gh-135815: skip `netrc` security checks if `os.getuid` is missing 
(GH-135816) (#135826)

gh-135815: skip `netrc` security checks if `os.getuid` is missing (GH-135816)
(cherry picked from commit b57b619e34cdfc87b47943c988b0b4d69f8f1fe4)

Co-authored-by: Bénédikt Tran <10796600+picn...@users.noreply.github.com>

files:
A Misc/NEWS.d/next/Library/2025-06-22-16-23-44.gh-issue-135815.0DandH.rst
M Doc/library/netrc.rst
M Lib/netrc.py
M Lib/test/test_netrc.py

diff --git a/Doc/library/netrc.rst b/Doc/library/netrc.rst
index f6260383b2b057..74c97e8c9a9759 100644
--- a/Doc/library/netrc.rst
+++ b/Doc/library/netrc.rst
@@ -24,12 +24,14 @@ the Unix :program:`ftp` program and other FTP clients.
    a :exc:`FileNotFoundError` exception will be raised.
    Parse errors will raise :exc:`NetrcParseError` with diagnostic
    information including the file name, line number, and terminating token.
+
    If no argument is specified on a POSIX system, the presence of passwords in
    the :file:`.netrc` file will raise a :exc:`NetrcParseError` if the file
    ownership or permissions are insecure (owned by a user other than the user
    running the process, or accessible for read or write by any other user).
    This implements security behavior equivalent to that of ftp and other
-   programs that use :file:`.netrc`.
+   programs that use :file:`.netrc`. Such security checks are not available
+   on platforms that do not support :func:`os.getuid`.
 
    .. versionchanged:: 3.4 Added the POSIX permission check.
 
diff --git a/Lib/netrc.py b/Lib/netrc.py
index b285fd8e357ddb..bd003e80a48081 100644
--- a/Lib/netrc.py
+++ b/Lib/netrc.py
@@ -7,6 +7,19 @@
 __all__ = ["netrc", "NetrcParseError"]
 
 
+def _can_security_check():
+    # On WASI, getuid() is indicated as a stub but it may also be missing.
+    return os.name == 'posix' and hasattr(os, 'getuid')
+
+
+def _getpwuid(uid):
+    try:
+        import pwd
+        return pwd.getpwuid(uid)[0]
+    except (ImportError, LookupError):
+        return f'uid {uid}'
+
+
 class NetrcParseError(Exception):
     """Exception raised on syntax errors in the .netrc file."""
     def __init__(self, msg, filename=None, lineno=None):
@@ -142,18 +155,12 @@ def _parse(self, file, fp, default_netrc):
             self._security_check(fp, default_netrc, self.hosts[entryname][0])
 
     def _security_check(self, fp, default_netrc, login):
-        if os.name == 'posix' and default_netrc and login != "anonymous":
+        if _can_security_check() and default_netrc and login != "anonymous":
             prop = os.fstat(fp.fileno())
-            if prop.st_uid != os.getuid():
-                import pwd
-                try:
-                    fowner = pwd.getpwuid(prop.st_uid)[0]
-                except KeyError:
-                    fowner = 'uid %s' % prop.st_uid
-                try:
-                    user = pwd.getpwuid(os.getuid())[0]
-                except KeyError:
-                    user = 'uid %s' % os.getuid()
+            current_user_id = os.getuid()
+            if prop.st_uid != current_user_id:
+                fowner = _getpwuid(prop.st_uid)
+                user = _getpwuid(current_user_id)
                 raise NetrcParseError(
                     (f"~/.netrc file owner ({fowner}, {user}) does not match"
                      " current user"))
diff --git a/Lib/test/test_netrc.py b/Lib/test/test_netrc.py
index 81e11a293cc4c8..9d720f627102e3 100644
--- a/Lib/test/test_netrc.py
+++ b/Lib/test/test_netrc.py
@@ -1,11 +1,7 @@
 import netrc, os, unittest, sys, textwrap
+from test import support
 from test.support import os_helper
 
-try:
-    import pwd
-except ImportError:
-    pwd = None
-
 temp_filename = os_helper.TESTFN
 
 class NetrcTestCase(unittest.TestCase):
@@ -269,9 +265,14 @@ def 
test_comment_at_end_of_machine_line_pass_has_hash(self):
             machine bar.domain.com login foo password pass
             """, '#pass')
 
+    @unittest.skipUnless(support.is_wasi, 'WASI only test')
+    def test_security_on_WASI(self):
+        self.assertFalse(netrc._can_security_check())
+        self.assertEqual(netrc._getpwuid(0), 'uid 0')
+        self.assertEqual(netrc._getpwuid(123456), 'uid 123456')
 
     @unittest.skipUnless(os.name == 'posix', 'POSIX only test')
-    @unittest.skipIf(pwd is None, 'security check requires pwd module')
+    @unittest.skipUnless(hasattr(os, 'getuid'), "os.getuid is required")
     @os_helper.skip_unless_working_chmod
     def test_security(self):
         # This test is incomplete since we are normally not run as root and
diff --git 
a/Misc/NEWS.d/next/Library/2025-06-22-16-23-44.gh-issue-135815.0DandH.rst 
b/Misc/NEWS.d/next/Library/2025-06-22-16-23-44.gh-issue-135815.0DandH.rst
new file mode 100644
index 00000000000000..0f4a68bf745a8e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-06-22-16-23-44.gh-issue-135815.0DandH.rst
@@ -0,0 +1,2 @@
+:mod:`netrc`: skip security checks if :func:`os.getuid` is missing.
+Patch by Bénédikt Tran.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: arch...@mail-archive.com

Reply via email to