Skip to content

Commit

Permalink
[enhancement] - Find module - Adding directory exclusion logic with d…
Browse files Browse the repository at this point in the history
…epth-based exclusion control (#107)

* Adding exclusion logic for find method

* Adding directory exclusion logic
  • Loading branch information
ghecko authored Oct 11, 2024
1 parent 8fba2f7 commit 5034419
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 22 deletions.
35 changes: 24 additions & 11 deletions smbclientng/core/SMBSession.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def ping_smb_session(self):

# Operations

def find(self, paths=[], callback=None):
def find(self, paths=[], callback=None, excluded_dirs=[], exclude_dir_depth=0):
"""
Finds files and directories on the SMB share based on the provided paths and executes a callback function on each entry.
Expand All @@ -250,6 +250,7 @@ def find(self, paths=[], callback=None):
paths (list, optional): A list of paths to start the search from. Defaults to an empty list.
callback (function, optional): A function to be called on each entry found. The function should accept three arguments:
the entry object, the full path of the entry, and the current depth of recursion. Defaults to None.
excluded_dirs (list, optional): A list of directories to exclude from the search. Defaults to None.
Note:
If the callback function is None, the method will print an error message and return without performing any action.
Expand All @@ -262,32 +263,44 @@ def recurse_action(paths=[], depth=0, callback=None):
next_directories_to_explore = []

for path in paths:
normalized_path = ntpath.normpath(path)
# Exclude paths that are in the exclude list based on depth
if exclude_dir_depth == -1 or depth == exclude_dir_depth:
if any(excluded.lower() == ntpath.basename(normalized_path).lower() for excluded in excluded_dirs):
continue # Skip this path

remote_smb_path = ntpath.normpath(self.smb_cwd + ntpath.sep + path)
entries = []

try:
entries = self.smbClient.listPath(
shareName=self.smb_share,
shareName=self.smb_share,
path=(remote_smb_path + ntpath.sep + '*')
)
except impacket.smbconnection.SessionError as err:
continue
continue
# Remove dot names
entries = [e for e in entries if e.get_longname() not in [".", ".."]]
# Sort the entries ignoring case
entries = sorted(entries, key=lambda x:x.get_longname().lower())
entries = sorted(entries, key=lambda x: x.get_longname().lower())

for entry in entries:
fullpath = ntpath.join(path, entry.get_longname())

if entry.is_directory():
fullpath = path + ntpath.sep + entry.get_longname() + ntpath.sep
# Exclude directories during traversal based on exclude_dir_depth
if exclude_dir_depth == -1 or depth + 1 == exclude_dir_depth:
if any(excluded.lower() == entry.get_longname().lower() for excluded in excluded_dirs):
continue # Skip this directory

next_directories_to_explore.append(fullpath)
else:
fullpath = path + ntpath.sep + entry.get_longname()

# Process the entry
fullpath = re.sub(r'\\\\+', r'\\', fullpath)
callback(entry, fullpath, depth)

return next_directories_to_explore
#

if callback is not None:
depth = 0
while len(paths) != 0:
Expand Down
23 changes: 12 additions & 11 deletions smbclientng/modules/Find.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ def parseArgs(self, arguments):
parser.add_argument("-iname", type=str, 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", type=str, action='append', default=[], help="Subdirectories to exclude from the search.")
parser.add_argument("-exclude-dir-depth", type=int, default=0, help="Specify the depth at which to exclude directories. Use -1 to exclude directories at all levels. Default is 0 (initial level only).")
# parser.add_argument("-mtime", type=str, help="File's data was last modified n*24 hours ago")
# parser.add_argument("-ctime", type=str, help="File's status was last changed n*24 hours ago")
# parser.add_argument("-atime", type=str, help="File was last accessed n*24 hours ago")

# Adding actions
parser.add_argument("-ls", action="store_true", default=False, help="List current file in ls -dils format on standard output.")
parser.add_argument("-download", action="store_true", default=False, help="List current file in ls -dils format on standard output.")
Expand Down Expand Up @@ -93,7 +95,7 @@ def __find_callback(self, entry, fullpath, depth):
if self.options.maxdepth is not None:
if depth > self.options.maxdepth:
do_print_results = False

if do_print_results:
do_print_entry = False
# Print directory
Expand All @@ -102,7 +104,7 @@ def __find_callback(self, entry, fullpath, depth):
# No name filtering
if self.options.name is None and self.options.iname is None:
do_print_entry = True

# Filtering on names case sensitive
elif self.options.name is not None:
if '*' in self.options.name:
Expand Down Expand Up @@ -130,7 +132,7 @@ def __find_callback(self, entry, fullpath, depth):
do_print_entry = False
else:
do_print_entry = (entry.get_longname().lower() == self.options.iname.lower())

# Print file
else:
if (self.options.type == 'f' or self.options.type is None):
Expand Down Expand Up @@ -175,7 +177,7 @@ def __find_callback(self, entry, fullpath, depth):
size = int(size_filter[1:-1])
units = ["B","K","M","G","T"]
if size_filter[-1].upper() in units:
size = size * (1024**units.index(size_filter[-1]))
size = size * (1024 ** units.index(size_filter[-1]))
else:
pass

Expand Down Expand Up @@ -203,7 +205,7 @@ def __find_callback(self, entry, fullpath, depth):
output_str = ("%s" % fullpath.replace(ntpath.sep, '/'))
else:
output_str = ("%s" % fullpath.replace(ntpath.sep, '/'))

if self.options.outputfile is not None:
with open(self.options.outputfile, 'a') as f:
f.write(output_str + '\n')
Expand Down Expand Up @@ -240,16 +242,15 @@ def run(self, arguments):
for path in list(set(self.options.paths)):
next_directories_to_explore.append(ntpath.normpath(path) + ntpath.sep)
next_directories_to_explore = sorted(list(set(next_directories_to_explore)))

self.smbSession.find(
paths=next_directories_to_explore,
callback=self.__find_callback
callback=self.__find_callback,
excluded_dirs=self.options.exclude_dir,
exclude_dir_depth=self.options.exclude_dir_depth
)

except (BrokenPipeError, KeyboardInterrupt) as e:
print("[!] Interrupted.")
self.smbSession.close_smb_session()
self.smbSession.init_smb_session()



0 comments on commit 5034419

Please sign in to comment.