From 98818e7d63859fd7ccf9dea5433556c234b66224 Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 3 Nov 2022 23:17:24 +0000 Subject: [PATCH] smb: workaround impacket response size limit --- README.md | 1 + copyparty/__main__.py | 1 + copyparty/smbd.py | 42 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ced74d87..9b8e428d 100644 --- a/README.md +++ b/README.md @@ -755,6 +755,7 @@ some **BIG WARNINGS** specific to SMB/CIFS, in decreasing importance: * [shadowing](#shadowing) probably works as expected but no guarantees and some minor issues, +* clients only see the first ~400 files in big folders; [impacket#1433](https://github.com/SecureAuthCorp/impacket/issues/1433) * hot-reload of server config (`/?reload=cfg`) only works for volumes, not account passwords * listens on the first `-i` interface only (default = 0.0.0.0 = all) * login doesn't work on winxp, but anonymous access is ok -- remove all accounts from copyparty config for that to work diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 8c3e80d5..e00108eb 100755 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -644,6 +644,7 @@ def run_argparse( ap2.add_argument("--smb1", action="store_true", help="disable SMBv2, only enable SMBv1 (CIFS)") ap2.add_argument("--smb-port", metavar="PORT", type=int, default=445, help="port to listen on -- if you change this value, you must NAT from TCP:445 to this port using iptables or similar") ap2.add_argument("--smb-dbg", action="store_true", help="show debug messages") + ap2.add_argument("--smb-nwa-1", action="store_true", help="disable impacket#1433 workaround (truncate directory listings to 64kB)") ap2 = ap.add_argument_group('opt-outs') ap2.add_argument("-nw", action="store_true", help="never write anything to disk (debug/benchmark)") diff --git a/copyparty/smbd.py b/copyparty/smbd.py index 18efd041..7e0ec42c 100644 --- a/copyparty/smbd.py +++ b/copyparty/smbd.py @@ -11,18 +11,20 @@ from types import SimpleNamespace from .__init__ import ANYWIN, TYPE_CHECKING from .authsrv import LEELOO_DALLAS, VFS -from .util import Daemon, min_ex from .bos import bos +from .util import Daemon, min_ex if True: # pylint: disable=using-constant-test from typing import Any + from .util import RootLogger + if TYPE_CHECKING: from .svchub import SvcHub class HLog(logging.Handler): - def __init__(self, log_func: Any) -> None: + def __init__(self, log_func: "RootLogger") -> None: logging.Handler.__init__(self) self.log_func = log_func @@ -35,7 +37,17 @@ class HLog(logging.Handler): def emit(self, record: logging.LogRecord) -> None: msg = self.format(record) - self.log_func("smb", msg) + lv = record.levelno + if lv < logging.INFO: + c = 6 + elif lv < logging.WARNING: + c = 0 + elif lv < logging.ERROR: + c = 3 + else: + c = 1 + + self.log_func("smb", msg, c) class SMB(object): @@ -137,9 +149,27 @@ class SMB(object): _, vfs_ls, vfs_virt = vfs.ls( rem, LEELOO_DALLAS, not self.args.no_scandir, [[False, False]] ) - ls = [x[0] for x in vfs_ls] - ls.extend(vfs_virt.keys()) - return ls + dirs = [x[0] for x in vfs_ls if stat.S_ISDIR(x[1].st_mode)] + fils = [x[0] for x in vfs_ls if x[0] not in dirs] + ls = list(vfs_virt.keys()) + dirs + fils + if self.args.smb_nwa_1: + return ls + + # clients crash somewhere around 65760 byte + ret = [] + sz = 112 * 2 # ['.', '..'] + for n, fn in enumerate(ls): + if sz >= 64000: + t = "listing only %d of %d files (%d byte); see impacket#1433" + logging.warning(t, n, len(ls), sz) + break + + nsz = len(fn.encode("utf-16", "replace")) + nsz = ((nsz + 7) // 8) * 8 + sz += 104 + nsz + ret.append(fn) + + return ret def _open( self, vpath: str, flags: int, *a: Any, chmod: int = 0o777, **ka: Any