From 1d824cb26c7487d186bd34ff58535e7794b4b60b Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 4 Jun 2021 02:23:46 +0200 Subject: [PATCH] add volume lister / containment checker --- README.md | 1 - copyparty/__main__.py | 14 +++++++ copyparty/authsrv.py | 87 +++++++++++++++++++++++++++++++++++++++++++ copyparty/svchub.py | 2 + 4 files changed, 103 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 40342c00..17dcebee 100644 --- a/README.md +++ b/README.md @@ -520,7 +520,6 @@ in the `scripts` folder: roughly sorted by priority -* traversal report per-user * readme.md as epilogue * single sha512 across all up2k chunks? maybe * reduce up2k roundtrips diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 6c8885e3..a5b3f5d2 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -225,6 +225,19 @@ def run_argparse(argv, formatter): --ciphers help = available ssl/tls ciphers, --ssl-ver help = available ssl/tls versions, default is what python considers safe, usually >= TLS1 + + values for --ls: + "USR" is a user to browse as; * is anonymous, ** is all users + "VOL" is a single volume to scan, default is * (all vols) + "FLAG" is flags; + "v" in addition to realpaths, print usernames and vpaths + "ln" only prints symlinks leaving the volume mountpoint + "p" exits 1 if any such symlinks are found + "r" resumes startup after the listing + examples: + --ls '**' # list all files which are possible to read + --ls '**,*,ln' # check for dangerous symlinks + --ls '**,*,ln,p,r' # check, then start normally if safe """ ), ) @@ -288,6 +301,7 @@ def run_argparse(argv, formatter): ap2.add_argument("--ssl-log", metavar="PATH", help="log master secrets") ap2 = ap.add_argument_group('debug options') + ap2.add_argument("--ls", metavar="U[,V[,F]]", help="scan all volumes") ap2.add_argument("--log-conn", action="store_true", help="print tcp-server msgs") ap2.add_argument("--no-sendfile", action="store_true", help="disable sendfile") ap2.add_argument("--no-scandir", action="store_true", help="disable scandir") diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index a99360b9..3d92b7e1 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -559,3 +559,90 @@ class AuthSrv(object): # import pprint # pprint.pprint({"usr": user, "rd": mread, "wr": mwrite, "mnt": mount}) + + def dbg_ls(self): + users = self.args.ls + vols = "*" + flags = [] + + try: + users, vols = users.split(",", 1) + except: + pass + + try: + vols, flags = vols.split(",", 1) + flags = flags.split(",") + except: + pass + + if users == "**": + users = list(self.user.keys()) + ["*"] + else: + users = [users] + + for u in users: + if u not in self.user and u != "*": + raise Exception("user not found: " + u) + + if vols == "*": + vols = ["/" + x for x in self.vfs.all_vols.keys()] + else: + vols = [vols] + + for v in vols: + if not v.startswith("/"): + raise Exception("volumes must start with /") + + if v[1:] not in self.vfs.all_vols: + raise Exception("volume not found: " + v) + + self.log({"users": users, "vols": vols, "flags": flags}) + for k, v in self.vfs.all_vols.items(): + self.log("/{}: read({}) write({})".format(k, v.uread, v.uwrite)) + + flag_v = "v" in flags + flag_ln = "ln" in flags + flag_p = "p" in flags + flag_r = "r" in flags + + n_bads = 0 + for v in vols: + v = v[1:] + vtop = "/{}/".format(v) if v else "/" + for u in users: + self.log("checking /{} as {}".format(v, u)) + try: + vn, _ = self.vfs.get(v, u, True, False) + except: + continue + + atop = vn.realpath + g = vn.walk("", "", u, True, not self.args.no_scandir, lstat=False) + for vpath, apath, files, _, _ in g: + fnames = [n[0] for n in files] + vpaths = [vpath + "/" + n for n in fnames] if vpath else fnames + vpaths = [vtop + x for x in vpaths] + apaths = [os.path.join(apath, n) for n in fnames] + files = list(zip(vpaths, apaths)) + + if flag_ln: + files = [x for x in files if not x[1].startswith(atop + os.sep)] + n_bads += len(files) + + if flag_v: + msg = [ + '# user "{}", vpath "{}"\n{}'.format(u, vp, ap) + for vp, ap in files + ] + else: + msg = [x[1] for x in files] + + if msg: + nuprint("\n".join(msg)) + + if n_bads and flag_p: + raise Exception("found symlink leaving volume, and strict is set") + + if not flag_r: + sys.exit(0) diff --git a/copyparty/svchub.py b/copyparty/svchub.py index d4c53146..8f50b373 100644 --- a/copyparty/svchub.py +++ b/copyparty/svchub.py @@ -39,6 +39,8 @@ class SvcHub(object): # jank goes here auth = AuthSrv(self.args, self.log, False) + if args.ls: + auth.dbg_ls() # initiate all services to manage self.tcpsrv = TcpSrv(self)