From 195b4afa8f26e0ac8e79c2cb485140c943ac4600 Mon Sep 17 00:00:00 2001 From: david-sarah Date: Mon, 7 Jun 2010 22:57:00 -0700 Subject: [PATCH] SFTP: ignore permissions when opening a file (needed for sshfs interoperability). --- src/allmydata/frontends/sftpd.py | 15 +++++++-------- src/allmydata/test/test_sftp.py | 24 ++++++++++++++++++------ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/allmydata/frontends/sftpd.py b/src/allmydata/frontends/sftpd.py index de401fd1..e09d845c 100644 --- a/src/allmydata/frontends/sftpd.py +++ b/src/allmydata/frontends/sftpd.py @@ -191,7 +191,7 @@ def _lsLine(name, attrs): return l -def _no_write(parent_readonly, child, metadata): +def _no_write(parent_readonly, child, metadata=None): """Whether child should be listed as having read-only permissions in parent.""" if child.is_unknown(): @@ -201,7 +201,7 @@ def _no_write(parent_readonly, child, metadata): elif parent_readonly or IDirectoryNode.providedBy(child): return True else: - return metadata.get('no-write', False) + return metadata is not None and metadata.get('no-write', False) def _populate_attrs(childnode, metadata, size=None): @@ -1326,10 +1326,6 @@ class SFTPUserHandler(ConchUser, PrefixingLogMixin): if (flags & FXF_WRITE) and root.is_readonly(): raise SFTPError(FX_PERMISSION_DENIED, "cannot write to a non-writeable filecap without a parent directory") - if (flags & FXF_WRITE) and root.is_mutable() and desired_metadata.get('no-write', False): - raise SFTPError(FX_PERMISSION_DENIED, - "cannot write to a mutable filecap without a parent directory, when the " - "specified permissions would require the link from the parent to be made read-only") if flags & FXF_EXCL: raise SFTPError(FX_FAILURE, "cannot create a file exclusively when it already exists") @@ -1346,7 +1342,7 @@ class SFTPUserHandler(ConchUser, PrefixingLogMixin): # reported as r--r--r--, which is appropriate because an immutable file can't be # written via this path. - metadata['no-write'] = _no_write(True, root, metadata) + metadata['no-write'] = _no_write(True, root) return self._make_file(file, userpath, flags, filenode=root, metadata=metadata) else: # case 2 @@ -1398,7 +1394,10 @@ class SFTPUserHandler(ConchUser, PrefixingLogMixin): if noisy: self.log("_got_child( (%r, %r) )" % (filenode, current_metadata), level=NOISY) metadata = update_metadata(current_metadata, desired_metadata, time()) - metadata['no-write'] = _no_write(parent_readonly, filenode, metadata) + + # Ignore the permissions of the desired_metadata in an open call. The permissions + # can only be set by setAttrs. + metadata['no-write'] = _no_write(parent_readonly, filenode, current_metadata) if filenode.is_unknown(): raise SFTPError(FX_PERMISSION_DENIED, diff --git a/src/allmydata/test/test_sftp.py b/src/allmydata/test/test_sftp.py index efba99e2..0bc20e87 100644 --- a/src/allmydata/test/test_sftp.py +++ b/src/allmydata/test/test_sftp.py @@ -573,12 +573,6 @@ class Handler(GridTestMixin, ShouldFailMixin, ReallyEqualMixin, unittest.TestCas self.shouldFailWithSFTPError(sftp.FX_PERMISSION_DENIED, "openFile readonly uri WRITE denied", self.handler.openFile, "uri/"+self.readonly_uri, sftp.FXF_WRITE, {})) - # cannot write to a mutable file by uri when no-write permissions are specified - d.addCallback(lambda ign: - self.shouldFailWithSFTPError(sftp.FX_PERMISSION_DENIED, "openFile mutable uri permissions:0444 WRITE denied", - self.handler.openFile, "uri/"+self.mutable_uri, sftp.FXF_WRITE, - {'permissions': 0444})) - # cannot create a file with the EXCL flag if it already exists d.addCallback(lambda ign: self.shouldFailWithSFTPError(sftp.FX_FAILURE, "openFile small WRITE|CREAT|EXCL failure", @@ -696,6 +690,16 @@ class Handler(GridTestMixin, ShouldFailMixin, ReallyEqualMixin, unittest.TestCas d.addCallback(lambda node: download_to_data(node)) d.addCallback(lambda data: self.failUnlessReallyEqual(data, "01234")) + # test WRITE | TRUNC with permissions: 0 + d.addCallback(lambda ign: + self.handler.openFile("newfile", sftp.FXF_WRITE | sftp.FXF_TRUNC, {'permissions': 0})) + d.addCallback(_write_trunc) + d.addCallback(lambda ign: self.root.get(u"newfile")) + d.addCallback(lambda node: download_to_data(node)) + d.addCallback(lambda data: self.failUnlessReallyEqual(data, "01234")) + d.addCallback(lambda ign: self.root.get_metadata_for(u"newfile")) + d.addCallback(lambda metadata: self.failIf(metadata.get('no-write', False), metadata)) + # test EXCL flag d.addCallback(lambda ign: self.handler.openFile("excl", sftp.FXF_WRITE | sftp.FXF_CREAT | @@ -824,6 +828,14 @@ class Handler(GridTestMixin, ShouldFailMixin, ReallyEqualMixin, unittest.TestCas d.addCallback(_check_same_file) d.addCallback(lambda data: self.failUnlessReallyEqual(data, "mutable new! contents")) + # ... and with permissions, which should be ignored + d.addCallback(lambda ign: + self.handler.openFile("mutable", sftp.FXF_WRITE, {'permissions': 0})) + d.addCallback(_write_mutable) + d.addCallback(lambda ign: self.root.get(u"mutable")) + d.addCallback(_check_same_file) + d.addCallback(lambda data: self.failUnlessReallyEqual(data, "mutable new! contents")) + # test READ | WRITE without CREAT or TRUNC d.addCallback(lambda ign: self.handler.openFile("small", sftp.FXF_READ | sftp.FXF_WRITE, {})) -- 2.45.2