Skip to content

Commit

Permalink
Mitigate file filter recursion issue in Find module
Browse files Browse the repository at this point in the history
  • Loading branch information
ghecko committed Nov 14, 2024
1 parent 96e6756 commit b09a601
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 20 deletions.
53 changes: 40 additions & 13 deletions smbclientng/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,16 +516,21 @@ def entry_matches_filters(entry, filters):
if 'type' in filters and filters['type'] != entry_type:
return False

# Filter by name
entry_name = entry.get_longname()
# Filter by name (case-sensitive)
if 'name' in filters:
pattern = filters['name']
if not fnmatch.fnmatchcase(entry_name, pattern):
name_patterns = filters['name']
if isinstance(name_patterns, str):
name_patterns = [name_patterns]
if not any(fnmatch.fnmatchcase(entry_name, pattern) for pattern in name_patterns):
return False

# Filter by name (case-insensitive)
if 'iname' in filters:
pattern = filters['iname'].lower()
if not fnmatch.fnmatch(entry_name.lower(), pattern):
iname_patterns = filters['iname']
if isinstance(iname_patterns, str):
iname_patterns = [iname_patterns]
entry_name_lower = entry_name.lower()
if not any(fnmatch.fnmatch(entry_name_lower, pattern.lower()) for pattern in iname_patterns):
return False

# Filter by size
Expand Down Expand Up @@ -575,6 +580,7 @@ def size_matches_filter(size, size_filter):
shareName=smb_share,
path=ntpath.join(base_path, '*')
)

entries = [e for e in entries if e.get_longname() not in ['.', '..']]
entries.sort(key=lambda e: (not e.is_directory(), e.get_longname().lower()))

Expand Down Expand Up @@ -605,15 +611,28 @@ def size_matches_filter(size, size_filter):
if (max_depth is not None and current_depth > max_depth) or current_depth < min_depth:
continue

# Apply entry filters
if filters:
if not entry_matches_filters(entry, filters):
continue

yield entry, fullpath, current_depth, is_last_entry

# Recursion for directories
if entry.is_directory():
yield_dir = True
if filters:
# Check if 'type' filter is specified
if 'type' in filters:
if filters['type'] == 'd':
yield_dir = True
else:
yield_dir = False
else:
# Filters are applied, but 'type' is not specified
# Assume filters are for files, prevent directory from being yielded
yield_dir = False
else:
# No filters, yield directories
yield_dir = True

# Yield the directory if it matches the criteria
if yield_dir:
yield entry, fullpath, current_depth, is_last_entry

if max_depth is None or current_depth < max_depth:
yield from smb_entry_iterator(
smb_client=smb_client,
Expand All @@ -625,6 +644,14 @@ def size_matches_filter(size, size_filter):
current_depth=current_depth + 1,
filters=filters
)
else:
# Apply filters
if filters:
if not entry_matches_filters(entry, filters):
continue

# Yield the file
yield entry, fullpath, current_depth, is_last_entry

except impacket.smbconnection.SessionError as err:
message = f"{err}. Base path: {base_path}"
Expand Down
21 changes: 14 additions & 7 deletions smbclientng/modules/Find.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ def parseArgs(self, arguments):
parser.add_argument("-q", "--quiet", action="store_true", default=False, help="Suppress normal output.")

# Adding options for filtering
parser.add_argument("-name", type=str, help="Base of file name (the path with the leading directories removed).")
parser.add_argument("-iname", type=str, help="Like -name, but the match is case insensitive.")
parser.add_argument("-name", action='append', help="Base of file name (the path with the leading directories removed).")
parser.add_argument("-iname", action='append', help="Like -name, but the match is case insensitive.")
parser.add_argument("-type", type=str, default=None, help="File type (e.g., f for regular file, d for directory).")
parser.add_argument("-size", type=str, help="File uses n units of space.")
parser.add_argument('--exclude-dir', action='append', default=[], metavar='DIRNAME[:DEPTH[:CASE]]',
Expand All @@ -65,16 +65,23 @@ def parseArgs(self, arguments):
parser.add_argument("-maxdepth", type=int, help="Descend at most levels (a non-negative integer) levels of directories below the command line arguments.")
parser.add_argument("-mindepth", type=int, help="Do not apply any tests or actions at levels less than levels (a non-negative integer).")

if len(arguments.strip()) == 0:
if not arguments.strip():
parser.print_help()
return None
else:
self.options = self.processArguments(parser, arguments)
# Parse the arguments safely
try:
args = parser.parse_args(arguments.split())
except SystemExit:
# argparse uses sys.exit(), which raises SystemExit
return None

if self.options is not None:
if len(self.options.paths) == 0:
# Check if paths are provided; if not, print help and exit
if not args.paths:
parser.print_help()
self.options = None
return None

self.options = args

return self.options

Expand Down

0 comments on commit b09a601

Please sign in to comment.