cpython: e5c4eb6b8e05 (original) (raw)
Mercurial > cpython
changeset 85728:e5c4eb6b8e05 2.6
#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. [#14984]
R David Murray rdmurray@bitdance.com | |
---|---|
date | Mon, 16 Sep 2013 13:48:44 -0400 |
parents | 8a6def3add5b |
children | 2e19c65d6688 1b673e0fd8f3 |
files | Doc/library/netrc.rst Lib/netrc.py Lib/test/test_netrc.py Misc/NEWS |
diffstat | 4 files changed, 56 insertions(+), 2 deletions(-)[+] [-] Doc/library/netrc.rst 6 Lib/netrc.py 23 Lib/test/test_netrc.py 23 Misc/NEWS 6 |
line wrap: on
line diff
--- a/Doc/library/netrc.rst
+++ b/Doc/library/netrc.rst
@@ -21,6 +21,12 @@ the Unix :program:ftp
program and othe
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
--- a/Lib/netrc.py +++ b/Lib/netrc.py @@ -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 NetrcParseError(Exception): class netrc: def init(self, file=None):
default_netrc = file is None[](#l2.16) if file is None:[](#l2.17) try:[](#l2.18) file = os.path.join(os.environ['HOME'], ".netrc")[](#l2.19)
@@ -77,6 +78,26 @@ class netrc: elif tt == 'account': account = lexer.get_token() elif tt == 'password':
if os.name == 'posix' and default_netrc:[](#l2.24)
prop = os.fstat(fp.fileno())[](#l2.25)
if prop.st_uid != os.getuid():[](#l2.26)
try:[](#l2.27)
fowner = pwd.getpwuid(prop.st_uid)[0][](#l2.28)
except KeyError:[](#l2.29)
fowner = 'uid %s' % prop.st_uid[](#l2.30)
try:[](#l2.31)
user = pwd.getpwuid(os.getuid())[0][](#l2.32)
except KeyError:[](#l2.33)
user = 'uid %s ' % os.getuid()[](#l2.34)
raise NetrcParseError([](#l2.35)
("~/.netrc file owner (%s) does not match"[](#l2.36)
" current user (%s)") % (fowner, user),[](#l2.37)
file, lexer.lineno)[](#l2.38)
if (prop.st_mode & (stat.S_IRWXG | stat.S_IRWXO)):[](#l2.39)
raise NetrcParseError([](#l2.40)
"~/.netrc access too permissive: access"[](#l2.41)
" permissions must restrict access to only"[](#l2.42)
" the owner", file, lexer.lineno)[](#l2.43) password = lexer.get_token()[](#l2.44) else:[](#l2.45) raise NetrcParseError("bad follower token %r" % tt,[](#l2.46)
--- a/Lib/test/test_netrc.py +++ b/Lib/test/test_netrc.py @@ -32,7 +32,7 @@ class NetrcTestCase(unittest.TestCase): def tearDown (self): del self.netrc
os.unlink(temp_filename)[](#l3.7)
test_support.unlink(temp_filename)[](#l3.8)
def test_case_1(self): self.assert_(self.netrc.macros == {'macro1':['line1\n', 'line2\n'], @@ -41,6 +41,27 @@ class NetrcTestCase(unittest.TestCase): 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):[](#l3.17)
# This test is incomplete since we are normally not run as root and[](#l3.18)
# therefore can't test the file ownership being wrong.[](#l3.19)
os.unlink(temp_filename)[](#l3.20)
d = test_support.TESTFN[](#l3.21)
try:[](#l3.22)
os.mkdir(d)[](#l3.23)
fn = os.path.join(d, '.netrc')[](#l3.24)
with open(fn, 'wt') as f:[](#l3.25)
f.write(TEST_NETRC)[](#l3.26)
with test_support.EnvironmentVarGuard() as environ:[](#l3.27)
environ.set('HOME', d)[](#l3.28)
os.chmod(fn, 0600)[](#l3.29)
self.netrc = netrc.netrc()[](#l3.30)
self.test_case_1()[](#l3.31)
os.chmod(fn, 0622)[](#l3.32)
self.assertRaises(netrc.NetrcParseError, netrc.netrc)[](#l3.33)
finally:[](#l3.34)
test_support.rmtree(d)[](#l3.35)
+ def test_main(): test_support.run_unittest(NetrcTestCase)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -13,6 +13,12 @@ Core and Builtins Library ------- +- Issue #14984: On POSIX systems, when netrc is called without a filename