diff --git a/smbclientng/core/utils.py b/smbclientng/core/utils.py index 73bf0d9..27b853b 100644 --- a/smbclientng/core/utils.py +++ b/smbclientng/core/utils.py @@ -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 @@ -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())) @@ -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, @@ -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}" diff --git a/smbclientng/modules/Find.py b/smbclientng/modules/Find.py index 1fdaecc..30fb897 100644 --- a/smbclientng/modules/Find.py +++ b/smbclientng/modules/Find.py @@ -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]]', @@ -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