changeset: 85728:e5c4eb6b8e05 branch: 2.6 parent: 85714:8a6def3add5b user: R David Murray date: Mon Sep 16 13:48:44 2013 -0400 files: Doc/library/netrc.rst Lib/netrc.py Lib/test/test_netrc.py Misc/NEWS description: #14984: On POSIX, enforce permissions when reading default .netrc. Initial patch by Bruno Piguet. This is implemented as if a useful .netrc file could exist without passwords, which is possible in the general case; but in fact our netrc implementation does not support it. Fixing that issue will be an enhancement. diff -r 8a6def3add5b -r e5c4eb6b8e05 Doc/library/netrc.rst --- a/Doc/library/netrc.rst Sun Sep 15 13:11:47 2013 -0400 +++ b/Doc/library/netrc.rst Mon Sep 16 13:48:44 2013 -0400 @@ -21,6 +21,12 @@ no argument is given, the file :file:`.netrc` in the user's home directory will be read. 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`. .. exception:: NetrcParseError diff -r 8a6def3add5b -r e5c4eb6b8e05 Lib/netrc.py --- a/Lib/netrc.py Sun Sep 15 13:11:47 2013 -0400 +++ b/Lib/netrc.py Mon Sep 16 13:48:44 2013 -0400 @@ -2,7 +2,7 @@ # Module and documentation by Eric S. Raymond, 21 Dec 1998 -import os, shlex +import os, stat, shlex, pwd __all__ = ["netrc", "NetrcParseError"] @@ -21,6 +21,7 @@ class netrc: def __init__(self, file=None): + default_netrc = file is None if file is None: try: file = os.path.join(os.environ['HOME'], ".netrc") @@ -77,6 +78,26 @@ elif tt == 'account': account = lexer.get_token() elif tt == 'password': + if os.name == 'posix' and default_netrc: + prop = os.fstat(fp.fileno()) + if prop.st_uid != os.getuid(): + 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() + raise NetrcParseError( + ("~/.netrc file owner (%s) does not match" + " current user (%s)") % (fowner, user), + file, lexer.lineno) + if (prop.st_mode & (stat.S_IRWXG | stat.S_IRWXO)): + raise NetrcParseError( + "~/.netrc access too permissive: access" + " permissions must restrict access to only" + " the owner", file, lexer.lineno) password = lexer.get_token() else: raise NetrcParseError("bad follower token %r" % tt, diff -r 8a6def3add5b -r e5c4eb6b8e05 Lib/test/test_netrc.py --- a/Lib/test/test_netrc.py Sun Sep 15 13:11:47 2013 -0400 +++ b/Lib/test/test_netrc.py Mon Sep 16 13:48:44 2013 -0400 @@ -32,7 +32,7 @@ def tearDown (self): del self.netrc - os.unlink(temp_filename) + test_support.unlink(temp_filename) def test_case_1(self): self.assert_(self.netrc.macros == {'macro1':['line1\n', 'line2\n'], @@ -41,6 +41,27 @@ self.assert_(self.netrc.hosts['foo'] == ('log1', 'acct1', 'pass1')) self.assert_(self.netrc.hosts['default'] == ('log2', None, 'pass2')) + if os.name == 'posix': + def test_security(self): + # This test is incomplete since we are normally not run as root and + # therefore can't test the file ownership being wrong. + os.unlink(temp_filename) + d = test_support.TESTFN + try: + os.mkdir(d) + fn = os.path.join(d, '.netrc') + with open(fn, 'wt') as f: + f.write(TEST_NETRC) + with test_support.EnvironmentVarGuard() as environ: + environ.set('HOME', d) + os.chmod(fn, 0600) + self.netrc = netrc.netrc() + self.test_case_1() + os.chmod(fn, 0622) + self.assertRaises(netrc.NetrcParseError, netrc.netrc) + finally: + test_support.rmtree(d) + def test_main(): test_support.run_unittest(NetrcTestCase) diff -r 8a6def3add5b -r e5c4eb6b8e05 Misc/NEWS --- a/Misc/NEWS Sun Sep 15 13:11:47 2013 -0400 +++ b/Misc/NEWS Mon Sep 16 13:48:44 2013 -0400 @@ -13,6 +13,12 @@ Library ------- +- Issue #14984: On POSIX systems, when netrc is called without a filename + argument (and therefore is reading the user's $HOME/.netrc file), it now + enforces the same security rules as typical ftp clients: the .netrc file must + be owned by the user that owns the process and must not be readable by any + other user. + - Issue #16248: Disable code execution from the user's home directory by tkinter when the -E flag is passed to Python. Patch by Zachary Ware.

AltStyle によって変換されたページ (->オリジナル) /