sftp: improve logging

This commit is contained in:
ed 2026-01-07 20:36:34 +00:00
parent 038af50777
commit 13055c6451
3 changed files with 35 additions and 7 deletions

View file

@ -286,6 +286,8 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
self.uname: str = ssh.uname # type: ignore
self.args = self.hub.args
self.asrv: "AuthSrv" = self.hub.asrv
self.v = self.args.sftpv
self.vv = self.args.sftpvv
if self.uname == LEELOO_DALLAS:
raise Exception("send her back")
@ -353,15 +355,19 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
return SFTP_FAILURE
def _list_folder(self, path: str) -> list[SATTR] | int:
if self.v:
self.log("ls(%s):" % (path,))
try:
ap, vn, rem = self.v2a(path, r=True)
except Pebkac:
try:
self.v2a(path, w=True)
self.log("ls(%s): [] (write-only)" % (path,))
return [] # display write-only folders as empty
except:
pass
if self.asrv.vfs.realpath or path.strip("/"):
self.log("ls(%s): EPERM" % (path,))
return SFTP_PERMISSION_DENIED
# list of accessible volumes
ret = []
@ -376,6 +382,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
except:
pass
ret.sort(key=lambda x: x.filename)
self.log("ls(%s): vfs-root; |%d|" % (path, len(ret)))
return ret
_, vfs_ls, vfs_virt = vn.ls(
@ -394,6 +401,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
if self.uname not in vn.axs.udot:
ret = [x for x in ret if not x.filename.split("/")[-1].startswith(".")]
ret.sort(key=lambda x: x.filename)
self.log("ls(%s): |%d|" % (path, len(ret)))
return ret
def stat(self, path: str) -> SATTR | int:
@ -457,10 +465,12 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
ap = os.path.join(vn.realpath, rem)
vf = vn.flags
except Pebkac as ex:
t = "denied open file [%s], iflag=%s, attr=%s, read=%s, write=%s: %s"
self.log(t % (vp, iflag, attr, rd, wr, ex))
t = "denied open file [%s], iflag=%s, read=%s, write=%s: %s"
self.log(t % (vp, iflag, rd, wr, ex))
return SFTP_PERMISSION_DENIED
self.log("open(%s, %x, %s)" % (vp, iflag, smode))
if wr:
try:
st = bos.stat(ap)
@ -496,6 +506,8 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
self.log(t, 3)
return SFTP_PERMISSION_DENIED
self.log("writing to [%s] => [%s]" % (vp, ap))
if wr and need_unlink: # type: ignore # !rm
assert td # type: ignore # !rm
if td >= -1 and td <= self.args.ftp_wt:
@ -520,12 +532,15 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
chmod = getattr(attr, "st_mode", None)
if chmod is None:
chmod = vf.get("chmod_f", 644)
self.log("open(%s, %x): client did not chmod" % (vp, iflag))
else:
self.log("open(%s, %x): client set chmod %s" % (vp, iflag, chmod))
try:
fd = os.open(ap, iflag, chmod)
except OSError as ex:
t = "failed to os.open [%s] -> [%s] with iflag [%s] and chmod [%s]"
self.log(t % (vp, ap, iflag, chmod), 3)
t = "failed to os.open [%s] -> [%s] with iflag [%s] and chmod [%s]: %r"
self.log(t % (vp, ap, iflag, chmod, ex), 3)
return paramiko.SFTPServer.convert_errno(ex.errno)
if iflag & os.O_CREAT:
@ -534,8 +549,8 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
try:
f = os.fdopen(fd, smode)
except OSError as ex:
t = "failed to os.fdpen [%s] -> [%s] with smode [%s]"
self.log(t % (vp, ap, smode), 3)
t = "failed to os.fdpen [%s] -> [%s] with smode [%s]: %r"
self.log(t % (vp, ap, smode, ex), 3)
return paramiko.SFTPServer.convert_errno(ex.errno)
ret = SFTP_FH(iflag)
@ -552,17 +567,20 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
return SFTP_FAILURE
def _remove(self, vp: str) -> int:
self.log("rm(%s)" % (vp,))
if self.args.no_del:
self.log("The delete feature is disabled in server config")
return SFTP_PERMISSION_DENIED
try:
self.hub.up2k.handle_rm(self.uname, self.ip, [vp], [], False, False)
self.log("rm(%s): ok" % (vp,))
return SFTP_OK
except Pebkac as ex:
t = "denied delete [%s]: %s"
self.log(t % (vp, ex))
return SFTP_PERMISSION_DENIED
except OSError as ex:
self.log("failed: rm(%s): %r" % (vp, ex))
return paramiko.SFTPServer.convert_errno(ex.errno)
def rename(self, oldpath: str, newpath: str) -> int:
@ -573,6 +591,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
return SFTP_FAILURE
def _rename(self, svp: str, dvp: str) -> int:
self.log("mv(%s, %s)" % (svp, dvp))
if self.args.no_mv:
self.log("The rename/move feature is disabled in server config")
svp = svp.strip("/")
@ -585,6 +604,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
self.log(t % (svp, dvp, ex))
return SFTP_PERMISSION_DENIED
except OSError as ex:
self.log("mv(%s, %s): %r" % (svp, dvp, ex))
return paramiko.SFTPServer.convert_errno(ex.errno)
def mkdir(self, path: str, attr: SATTR) -> int:
@ -595,6 +615,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
return SFTP_FAILURE
def _mkdir(self, vp: str, attr: SATTR) -> int:
self.log("mkdir(%s)" % (vp,))
try:
vn, rem = self.asrv.vfs.get(vp, self.uname, False, True)
ap = os.path.join(vn.realpath, rem)
@ -607,6 +628,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
self.log(t % (vp, ex))
return SFTP_PERMISSION_DENIED
except OSError as ex:
self.log("mkdir(%s): %r" % (vp, ex))
return paramiko.SFTPServer.convert_errno(ex.errno)
def rmdir(self, path: str) -> int:
@ -617,6 +639,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
return SFTP_FAILURE
def _rmdir(self, vp: str) -> int:
self.log("rmdir(%s)" % (vp,))
try:
vn, rem = self.asrv.vfs.get(vp, self.uname, False, False, will_del=True)
ap = os.path.join(vn.realpath, rem)
@ -627,6 +650,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
self.log(t % (vp, ex))
return SFTP_PERMISSION_DENIED
except OSError as ex:
self.log("rmdir(%s): %r" % (vp, ex))
return paramiko.SFTPServer.convert_errno(ex.errno)
def chattr(self, path: str, attr: SATTR) -> int:
@ -637,6 +661,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
return SFTP_FAILURE
def _chattr(self, vp: str, attr: SATTR) -> int:
self.log("chattr(%s, %s)" % (vp, attr))
try:
vn, rem = self.asrv.vfs.get(vp, self.uname, False, True, will_del=True)
ap = os.path.join(vn.realpath, rem)
@ -647,6 +672,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
self.log(t % (vp, ex))
return SFTP_PERMISSION_DENIED
except OSError as ex:
self.log("chattr(%s): %r" % (vp, ex))
return paramiko.SFTPServer.convert_errno(ex.errno)
def symlink(self, target_path: str, path: str) -> int:
@ -714,7 +740,7 @@ class Sftpd(object):
for ip in ips:
self._bind(ip)
self.log("listening on %s port %s" % (self.srv, args.sftp))
self.log("listening on %s port %s" % (self.bound, args.sftp))
def log(self, msg: str, c: Union[int, str] = 0) -> None:
self.hub.log("sftp", msg, c)

View file

@ -4182,6 +4182,7 @@ class Up2k(object):
st = bos.lstat(atop)
is_dir = stat.S_ISDIR(st.st_mode)
except:
# NOTE: "file not found" *sftpd
raise Pebkac(400, "file not found on disk (already deleted?)")
if "bcasechk" in vn.flags and not vn.casechk(rem, False):

View file

@ -377,6 +377,7 @@ IMPLICATIONS = [
["tftpvv", "tftpv"],
["nodupem", "nodupe"],
["no_dupe_m", "no_dupe"],
["sftpvv", "sftpv"],
["smbw", "smb"],
["smb1", "smb"],
["smbvvv", "smbvv"],