diff --git a/Lib/netrc.py b/Lib/netrc.py index c1358aac6a..bd003e80a4 100644 --- a/Lib/netrc.py +++ b/Lib/netrc.py @@ -2,11 +2,24 @@ # Module and documentation by Eric S. Raymond, 21 Dec 1998 -import os, shlex, stat +import os, stat __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 573d636de9..9d720f6271 100644 --- a/Lib/test/test_netrc.py +++ b/Lib/test/test_netrc.py @@ -1,10 +1,6 @@ import netrc, os, unittest, sys, textwrap -from test.support import os_helper, run_unittest - -try: - import pwd -except ImportError: - pwd = None +from test import support +from test.support import os_helper temp_filename = os_helper.TESTFN @@ -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 @@ -308,8 +309,6 @@ def test_security(self): self.assertEqual(nrc.hosts['foo.domain.com'], ('anonymous', '', 'pass')) -def test_main(): - run_unittest(NetrcTestCase) if __name__ == "__main__": - test_main() + unittest.main() diff --git a/vm/src/stdlib/mod.rs b/vm/src/stdlib/mod.rs index 60cb09f405..2c4442900b 100644 --- a/vm/src/stdlib/mod.rs +++ b/vm/src/stdlib/mod.rs @@ -46,8 +46,13 @@ pub mod posix; mod ctypes; #[cfg(windows)] pub(crate) mod msvcrt; -#[cfg(all(unix, not(any(target_os = "android", target_os = "redox"))))] + +#[cfg(all( + unix, + not(any(target_os = "ios", target_os = "wasi", target_os = "redox")) +))] mod pwd; + pub(crate) mod signal; pub mod sys; #[cfg(windows)] @@ -120,7 +125,10 @@ pub fn get_module_inits() -> StdlibMap { "_thread" => thread::make_module, } // Unix-only - #[cfg(all(unix, not(any(target_os = "android", target_os = "redox"))))] + #[cfg(all( + unix, + not(any(target_os = "ios", target_os = "wasi", target_os = "redox")) + ))] { "pwd" => pwd::make_module, } diff --git a/vm/src/stdlib/pwd.rs b/vm/src/stdlib/pwd.rs index 16570ff6be..71a8c6c81e 100644 --- a/vm/src/stdlib/pwd.rs +++ b/vm/src/stdlib/pwd.rs @@ -2,6 +2,7 @@ pub(crate) use pwd::make_module; +#[cfg_attr(target_os = "android", allow(unused_imports))] #[pymodule] mod pwd { use crate::{ @@ -26,6 +27,7 @@ mod pwd { pw_dir: String, pw_shell: String, } + #[pyclass(with(PyStructSequence))] impl Passwd {} @@ -91,6 +93,7 @@ mod pwd { } // TODO: maybe merge this functionality into nix? + #[cfg(not(target_os = "android"))] #[pyfunction] fn getpwall(vm: &VirtualMachine) -> PyResult> { // setpwent, getpwent, etc are not thread safe. Could use fgetpwent_r, but this is easier