mirror of
https://github.com/9001/copyparty.git
synced 2026-01-12 15:52:39 -07:00
sftp: improve logging
This commit is contained in:
parent
038af50777
commit
13055c6451
|
|
@ -286,6 +286,8 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
self.uname: str = ssh.uname # type: ignore
|
self.uname: str = ssh.uname # type: ignore
|
||||||
self.args = self.hub.args
|
self.args = self.hub.args
|
||||||
self.asrv: "AuthSrv" = self.hub.asrv
|
self.asrv: "AuthSrv" = self.hub.asrv
|
||||||
|
self.v = self.args.sftpv
|
||||||
|
self.vv = self.args.sftpvv
|
||||||
|
|
||||||
if self.uname == LEELOO_DALLAS:
|
if self.uname == LEELOO_DALLAS:
|
||||||
raise Exception("send her back")
|
raise Exception("send her back")
|
||||||
|
|
@ -353,15 +355,19 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
return SFTP_FAILURE
|
return SFTP_FAILURE
|
||||||
|
|
||||||
def _list_folder(self, path: str) -> list[SATTR] | int:
|
def _list_folder(self, path: str) -> list[SATTR] | int:
|
||||||
|
if self.v:
|
||||||
|
self.log("ls(%s):" % (path,))
|
||||||
try:
|
try:
|
||||||
ap, vn, rem = self.v2a(path, r=True)
|
ap, vn, rem = self.v2a(path, r=True)
|
||||||
except Pebkac:
|
except Pebkac:
|
||||||
try:
|
try:
|
||||||
self.v2a(path, w=True)
|
self.v2a(path, w=True)
|
||||||
|
self.log("ls(%s): [] (write-only)" % (path,))
|
||||||
return [] # display write-only folders as empty
|
return [] # display write-only folders as empty
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if self.asrv.vfs.realpath or path.strip("/"):
|
if self.asrv.vfs.realpath or path.strip("/"):
|
||||||
|
self.log("ls(%s): EPERM" % (path,))
|
||||||
return SFTP_PERMISSION_DENIED
|
return SFTP_PERMISSION_DENIED
|
||||||
# list of accessible volumes
|
# list of accessible volumes
|
||||||
ret = []
|
ret = []
|
||||||
|
|
@ -376,6 +382,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
ret.sort(key=lambda x: x.filename)
|
ret.sort(key=lambda x: x.filename)
|
||||||
|
self.log("ls(%s): vfs-root; |%d|" % (path, len(ret)))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
_, vfs_ls, vfs_virt = vn.ls(
|
_, vfs_ls, vfs_virt = vn.ls(
|
||||||
|
|
@ -394,6 +401,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
if self.uname not in vn.axs.udot:
|
if self.uname not in vn.axs.udot:
|
||||||
ret = [x for x in ret if not x.filename.split("/")[-1].startswith(".")]
|
ret = [x for x in ret if not x.filename.split("/")[-1].startswith(".")]
|
||||||
ret.sort(key=lambda x: x.filename)
|
ret.sort(key=lambda x: x.filename)
|
||||||
|
self.log("ls(%s): |%d|" % (path, len(ret)))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def stat(self, path: str) -> SATTR | int:
|
def stat(self, path: str) -> SATTR | int:
|
||||||
|
|
@ -457,10 +465,12 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
ap = os.path.join(vn.realpath, rem)
|
ap = os.path.join(vn.realpath, rem)
|
||||||
vf = vn.flags
|
vf = vn.flags
|
||||||
except Pebkac as ex:
|
except Pebkac as ex:
|
||||||
t = "denied open file [%s], iflag=%s, attr=%s, read=%s, write=%s: %s"
|
t = "denied open file [%s], iflag=%s, read=%s, write=%s: %s"
|
||||||
self.log(t % (vp, iflag, attr, rd, wr, ex))
|
self.log(t % (vp, iflag, rd, wr, ex))
|
||||||
return SFTP_PERMISSION_DENIED
|
return SFTP_PERMISSION_DENIED
|
||||||
|
|
||||||
|
self.log("open(%s, %x, %s)" % (vp, iflag, smode))
|
||||||
|
|
||||||
if wr:
|
if wr:
|
||||||
try:
|
try:
|
||||||
st = bos.stat(ap)
|
st = bos.stat(ap)
|
||||||
|
|
@ -496,6 +506,8 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
self.log(t, 3)
|
self.log(t, 3)
|
||||||
return SFTP_PERMISSION_DENIED
|
return SFTP_PERMISSION_DENIED
|
||||||
|
|
||||||
|
self.log("writing to [%s] => [%s]" % (vp, ap))
|
||||||
|
|
||||||
if wr and need_unlink: # type: ignore # !rm
|
if wr and need_unlink: # type: ignore # !rm
|
||||||
assert td # type: ignore # !rm
|
assert td # type: ignore # !rm
|
||||||
if td >= -1 and td <= self.args.ftp_wt:
|
if td >= -1 and td <= self.args.ftp_wt:
|
||||||
|
|
@ -520,12 +532,15 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
chmod = getattr(attr, "st_mode", None)
|
chmod = getattr(attr, "st_mode", None)
|
||||||
if chmod is None:
|
if chmod is None:
|
||||||
chmod = vf.get("chmod_f", 644)
|
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:
|
try:
|
||||||
fd = os.open(ap, iflag, chmod)
|
fd = os.open(ap, iflag, chmod)
|
||||||
except OSError as ex:
|
except OSError as ex:
|
||||||
t = "failed to os.open [%s] -> [%s] with iflag [%s] and chmod [%s]"
|
t = "failed to os.open [%s] -> [%s] with iflag [%s] and chmod [%s]: %r"
|
||||||
self.log(t % (vp, ap, iflag, chmod), 3)
|
self.log(t % (vp, ap, iflag, chmod, ex), 3)
|
||||||
return paramiko.SFTPServer.convert_errno(ex.errno)
|
return paramiko.SFTPServer.convert_errno(ex.errno)
|
||||||
|
|
||||||
if iflag & os.O_CREAT:
|
if iflag & os.O_CREAT:
|
||||||
|
|
@ -534,8 +549,8 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
try:
|
try:
|
||||||
f = os.fdopen(fd, smode)
|
f = os.fdopen(fd, smode)
|
||||||
except OSError as ex:
|
except OSError as ex:
|
||||||
t = "failed to os.fdpen [%s] -> [%s] with smode [%s]"
|
t = "failed to os.fdpen [%s] -> [%s] with smode [%s]: %r"
|
||||||
self.log(t % (vp, ap, smode), 3)
|
self.log(t % (vp, ap, smode, ex), 3)
|
||||||
return paramiko.SFTPServer.convert_errno(ex.errno)
|
return paramiko.SFTPServer.convert_errno(ex.errno)
|
||||||
|
|
||||||
ret = SFTP_FH(iflag)
|
ret = SFTP_FH(iflag)
|
||||||
|
|
@ -552,17 +567,20 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
return SFTP_FAILURE
|
return SFTP_FAILURE
|
||||||
|
|
||||||
def _remove(self, vp: str) -> int:
|
def _remove(self, vp: str) -> int:
|
||||||
|
self.log("rm(%s)" % (vp,))
|
||||||
if self.args.no_del:
|
if self.args.no_del:
|
||||||
self.log("The delete feature is disabled in server config")
|
self.log("The delete feature is disabled in server config")
|
||||||
return SFTP_PERMISSION_DENIED
|
return SFTP_PERMISSION_DENIED
|
||||||
try:
|
try:
|
||||||
self.hub.up2k.handle_rm(self.uname, self.ip, [vp], [], False, False)
|
self.hub.up2k.handle_rm(self.uname, self.ip, [vp], [], False, False)
|
||||||
|
self.log("rm(%s): ok" % (vp,))
|
||||||
return SFTP_OK
|
return SFTP_OK
|
||||||
except Pebkac as ex:
|
except Pebkac as ex:
|
||||||
t = "denied delete [%s]: %s"
|
t = "denied delete [%s]: %s"
|
||||||
self.log(t % (vp, ex))
|
self.log(t % (vp, ex))
|
||||||
return SFTP_PERMISSION_DENIED
|
return SFTP_PERMISSION_DENIED
|
||||||
except OSError as ex:
|
except OSError as ex:
|
||||||
|
self.log("failed: rm(%s): %r" % (vp, ex))
|
||||||
return paramiko.SFTPServer.convert_errno(ex.errno)
|
return paramiko.SFTPServer.convert_errno(ex.errno)
|
||||||
|
|
||||||
def rename(self, oldpath: str, newpath: str) -> int:
|
def rename(self, oldpath: str, newpath: str) -> int:
|
||||||
|
|
@ -573,6 +591,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
return SFTP_FAILURE
|
return SFTP_FAILURE
|
||||||
|
|
||||||
def _rename(self, svp: str, dvp: str) -> int:
|
def _rename(self, svp: str, dvp: str) -> int:
|
||||||
|
self.log("mv(%s, %s)" % (svp, dvp))
|
||||||
if self.args.no_mv:
|
if self.args.no_mv:
|
||||||
self.log("The rename/move feature is disabled in server config")
|
self.log("The rename/move feature is disabled in server config")
|
||||||
svp = svp.strip("/")
|
svp = svp.strip("/")
|
||||||
|
|
@ -585,6 +604,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
self.log(t % (svp, dvp, ex))
|
self.log(t % (svp, dvp, ex))
|
||||||
return SFTP_PERMISSION_DENIED
|
return SFTP_PERMISSION_DENIED
|
||||||
except OSError as ex:
|
except OSError as ex:
|
||||||
|
self.log("mv(%s, %s): %r" % (svp, dvp, ex))
|
||||||
return paramiko.SFTPServer.convert_errno(ex.errno)
|
return paramiko.SFTPServer.convert_errno(ex.errno)
|
||||||
|
|
||||||
def mkdir(self, path: str, attr: SATTR) -> int:
|
def mkdir(self, path: str, attr: SATTR) -> int:
|
||||||
|
|
@ -595,6 +615,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
return SFTP_FAILURE
|
return SFTP_FAILURE
|
||||||
|
|
||||||
def _mkdir(self, vp: str, attr: SATTR) -> int:
|
def _mkdir(self, vp: str, attr: SATTR) -> int:
|
||||||
|
self.log("mkdir(%s)" % (vp,))
|
||||||
try:
|
try:
|
||||||
vn, rem = self.asrv.vfs.get(vp, self.uname, False, True)
|
vn, rem = self.asrv.vfs.get(vp, self.uname, False, True)
|
||||||
ap = os.path.join(vn.realpath, rem)
|
ap = os.path.join(vn.realpath, rem)
|
||||||
|
|
@ -607,6 +628,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
self.log(t % (vp, ex))
|
self.log(t % (vp, ex))
|
||||||
return SFTP_PERMISSION_DENIED
|
return SFTP_PERMISSION_DENIED
|
||||||
except OSError as ex:
|
except OSError as ex:
|
||||||
|
self.log("mkdir(%s): %r" % (vp, ex))
|
||||||
return paramiko.SFTPServer.convert_errno(ex.errno)
|
return paramiko.SFTPServer.convert_errno(ex.errno)
|
||||||
|
|
||||||
def rmdir(self, path: str) -> int:
|
def rmdir(self, path: str) -> int:
|
||||||
|
|
@ -617,6 +639,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
return SFTP_FAILURE
|
return SFTP_FAILURE
|
||||||
|
|
||||||
def _rmdir(self, vp: str) -> int:
|
def _rmdir(self, vp: str) -> int:
|
||||||
|
self.log("rmdir(%s)" % (vp,))
|
||||||
try:
|
try:
|
||||||
vn, rem = self.asrv.vfs.get(vp, self.uname, False, False, will_del=True)
|
vn, rem = self.asrv.vfs.get(vp, self.uname, False, False, will_del=True)
|
||||||
ap = os.path.join(vn.realpath, rem)
|
ap = os.path.join(vn.realpath, rem)
|
||||||
|
|
@ -627,6 +650,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
self.log(t % (vp, ex))
|
self.log(t % (vp, ex))
|
||||||
return SFTP_PERMISSION_DENIED
|
return SFTP_PERMISSION_DENIED
|
||||||
except OSError as ex:
|
except OSError as ex:
|
||||||
|
self.log("rmdir(%s): %r" % (vp, ex))
|
||||||
return paramiko.SFTPServer.convert_errno(ex.errno)
|
return paramiko.SFTPServer.convert_errno(ex.errno)
|
||||||
|
|
||||||
def chattr(self, path: str, attr: SATTR) -> int:
|
def chattr(self, path: str, attr: SATTR) -> int:
|
||||||
|
|
@ -637,6 +661,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
return SFTP_FAILURE
|
return SFTP_FAILURE
|
||||||
|
|
||||||
def _chattr(self, vp: str, attr: SATTR) -> int:
|
def _chattr(self, vp: str, attr: SATTR) -> int:
|
||||||
|
self.log("chattr(%s, %s)" % (vp, attr))
|
||||||
try:
|
try:
|
||||||
vn, rem = self.asrv.vfs.get(vp, self.uname, False, True, will_del=True)
|
vn, rem = self.asrv.vfs.get(vp, self.uname, False, True, will_del=True)
|
||||||
ap = os.path.join(vn.realpath, rem)
|
ap = os.path.join(vn.realpath, rem)
|
||||||
|
|
@ -647,6 +672,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
|
||||||
self.log(t % (vp, ex))
|
self.log(t % (vp, ex))
|
||||||
return SFTP_PERMISSION_DENIED
|
return SFTP_PERMISSION_DENIED
|
||||||
except OSError as ex:
|
except OSError as ex:
|
||||||
|
self.log("chattr(%s): %r" % (vp, ex))
|
||||||
return paramiko.SFTPServer.convert_errno(ex.errno)
|
return paramiko.SFTPServer.convert_errno(ex.errno)
|
||||||
|
|
||||||
def symlink(self, target_path: str, path: str) -> int:
|
def symlink(self, target_path: str, path: str) -> int:
|
||||||
|
|
@ -714,7 +740,7 @@ class Sftpd(object):
|
||||||
for ip in ips:
|
for ip in ips:
|
||||||
self._bind(ip)
|
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:
|
def log(self, msg: str, c: Union[int, str] = 0) -> None:
|
||||||
self.hub.log("sftp", msg, c)
|
self.hub.log("sftp", msg, c)
|
||||||
|
|
|
||||||
|
|
@ -4182,6 +4182,7 @@ class Up2k(object):
|
||||||
st = bos.lstat(atop)
|
st = bos.lstat(atop)
|
||||||
is_dir = stat.S_ISDIR(st.st_mode)
|
is_dir = stat.S_ISDIR(st.st_mode)
|
||||||
except:
|
except:
|
||||||
|
# NOTE: "file not found" *sftpd
|
||||||
raise Pebkac(400, "file not found on disk (already deleted?)")
|
raise Pebkac(400, "file not found on disk (already deleted?)")
|
||||||
|
|
||||||
if "bcasechk" in vn.flags and not vn.casechk(rem, False):
|
if "bcasechk" in vn.flags and not vn.casechk(rem, False):
|
||||||
|
|
|
||||||
|
|
@ -377,6 +377,7 @@ IMPLICATIONS = [
|
||||||
["tftpvv", "tftpv"],
|
["tftpvv", "tftpv"],
|
||||||
["nodupem", "nodupe"],
|
["nodupem", "nodupe"],
|
||||||
["no_dupe_m", "no_dupe"],
|
["no_dupe_m", "no_dupe"],
|
||||||
|
["sftpvv", "sftpv"],
|
||||||
["smbw", "smb"],
|
["smbw", "smb"],
|
||||||
["smb1", "smb"],
|
["smb1", "smb"],
|
||||||
["smbvvv", "smbvv"],
|
["smbvvv", "smbvv"],
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue