Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[enhancement] Implemented output to a file in find command, fixes #78 #89

Merged
merged 2 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 83 additions & 43 deletions smbclientng/core/SMBSession.py
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ def rm(self, path=None):
if self.config.debug:
traceback.print_exc()

def tree(self, path=None):
def tree(self, path=None, quiet=False, outputfile=None):
"""
Recursively lists the directory structure of the SMB share starting from the specified path.

Expand All @@ -1056,7 +1056,7 @@ def tree(self, path=None):
Defaults to the root of the current share.
"""

def recurse_action(base_dir="", path=[], prompt=[]):
def recurse_action(base_dir="", path=[], prompt=[], quiet=False, outputfile=None):
bars = ["│ ", "├── ", "└── "]

remote_smb_path = ntpath.normpath(base_dir + ntpath.sep + ntpath.sep.join(path))
Expand All @@ -1070,10 +1070,14 @@ def recurse_action(base_dir="", path=[], prompt=[]):
except impacket.smbconnection.SessionError as err:
code, const, text = err.getErrorCode(), err.getErrorString()[0], err.getErrorString()[1]
errmsg = "Error 0x%08x (%s): %s" % (code, const, text)
if self.config.no_colors:
self.logger.print("%s%s" % (''.join(prompt+[bars[2]]), errmsg))
else:
self.logger.print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), errmsg))
if not quiet:
if self.config.no_colors:
self.logger.print("%s%s" % (''.join(prompt+[bars[2]]), errmsg))
else:
self.logger.print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), errmsg))
if outputfile is not None:
with open(outputfile, 'a') as f:
f.write("%s%s\n" % (''.join(prompt+[bars[2]]), errmsg))
return

entries = [e for e in entries if e.get_longname() not in [".", ".."]]
Expand All @@ -1087,77 +1091,111 @@ def recurse_action(base_dir="", path=[], prompt=[]):
# This is the first entry
if index == 0:
if entry.is_directory():
if self.config.no_colors:
self.logger.print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
if not quiet:
if self.config.no_colors:
self.logger.print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
if outputfile is not None:
with open(outputfile, 'a') as f:
f.write("%s%s\\\n" % (''.join(prompt+[bars[1]]), entry.get_longname()))

recurse_action(
base_dir=base_dir,
path=path+[entry.get_longname()],
prompt=prompt+["│ "]
)
else:
if self.config.no_colors:
self.logger.print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))

if not quiet:
if self.config.no_colors:
self.logger.print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))
if outputfile is not None:
with open(outputfile, 'a') as f:
f.write("%s%s\n" % (''.join(prompt+[bars[1]]), entry.get_longname()))
# This is the last entry
elif index == len(entries):
if entry.is_directory():
if self.config.no_colors:
self.logger.print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
if not quiet:
if self.config.no_colors:
self.logger.print()
else:
self.logger.print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
if outputfile is not None:
with open(outputfile, 'a') as f:
f.write("%s%s\\\n" % (''.join(prompt+[bars[2]]), entry.get_longname()))
recurse_action(
base_dir=base_dir,
path=path+[entry.get_longname()],
prompt=prompt+[" "]
)
else:
if self.config.no_colors:
self.logger.print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))

if not quiet:
if self.config.no_colors:
self.logger.print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))
if outputfile is not None:
with open(outputfile, 'a') as f:
f.write("%s%s\n" % (''.join(prompt+[bars[2]]), entry.get_longname()))
# These are entries in the middle
else:
if entry.is_directory():
if self.config.no_colors:
self.logger.print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
if not quiet:
if self.config.no_colors:
self.logger.print("%s%s\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[1]]), entry.get_longname()))
if outputfile is not None:
with open(outputfile, 'a') as f:
f.write("%s%s\\\n" % (''.join(prompt+[bars[1]]), entry.get_longname()))
recurse_action(
base_dir=base_dir,
path=path+[entry.get_longname()],
prompt=prompt+["│ "]
)
else:
if self.config.no_colors:
self.logger.print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))

if not quiet:
if self.config.no_colors:
self.logger.print("%s%s" % (''.join(prompt+[bars[1]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry.get_longname()))
if outputfile is not None:
with open(outputfile, 'a') as f:
f.write("%s%s\n" % (''.join(prompt+[bars[1]]), entry.get_longname()))
#
elif len(entries) == 1:
entry = entries[0]
if entry.is_directory():
if self.config.no_colors:
self.logger.print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
if not quiet:
if self.config.no_colors:
self.logger.print("%s%s\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1;96m%s\x1b[0m\\" % (''.join(prompt+[bars[2]]), entry.get_longname()))
if outputfile is not None:
with open(outputfile, 'a') as f:
f.write("%s%s\\\n" % (''.join(prompt+[bars[2]]), entry.get_longname()))
recurse_action(
base_dir=base_dir,
path=path+[entry.get_longname()],
prompt=prompt+[" "]
)
else:
if self.config.no_colors:
self.logger.print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))

if not quiet:
if self.config.no_colors:
self.logger.print("%s%s" % (''.join(prompt+[bars[2]]), entry.get_longname()))
else:
self.logger.print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry.get_longname()))
if outputfile is not None:
with open(outputfile, 'a') as f:
f.write("%s%s\n" % (''.join(prompt+[bars[2]]), entry.get_longname()))
# Entrypoint
if outputfile is not None:
if not os.path.exists(os.path.dirname(outputfile)):
os.makedirs(os.path.dirname(outputfile))
open(outputfile, 'w').close()

try:
if self.config.no_colors:
self.logger.print("%s\\" % path)
Expand All @@ -1166,7 +1204,9 @@ def recurse_action(base_dir="", path=[], prompt=[]):
recurse_action(
base_dir=self.smb_cwd,
path=[path],
prompt=[""]
prompt=[""],
quiet=quiet,
outputfile=outputfile
)
except (BrokenPipeError, KeyboardInterrupt) as e:
self.logger.error("Interrupted.")
Expand Down
11 changes: 7 additions & 4 deletions smbclientng/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,19 @@ def windows_ls_entry(entry, config, pathToPrint=None):

date_str = datetime.datetime.fromtimestamp(entry.get_atime_epoch()).strftime("%Y-%m-%d %H:%M")

output_str = ""
if entry.is_directory():
if config.no_colors:
print("%s %10s %s %s\\" % (meta_string, size_str, date_str, pathToPrint))
output_str = ("%s %10s %s %s\\" % (meta_string, size_str, date_str, pathToPrint))
else:
print("%s %10s %s \x1b[1;96m%s\x1b[0m\\" % (meta_string, size_str, date_str, pathToPrint))
output_str = ("%s %10s %s \x1b[1;96m%s\x1b[0m\\" % (meta_string, size_str, date_str, pathToPrint))
else:
if config.no_colors:
print("%s %10s %s %s" % (meta_string, size_str, date_str, pathToPrint))
output_str = ("%s %10s %s %s" % (meta_string, size_str, date_str, pathToPrint))
else:
print("%s %10s %s \x1b[1m%s\x1b[0m" % (meta_string, size_str, date_str, pathToPrint))
output_str = ("%s %10s %s \x1b[1m%s\x1b[0m" % (meta_string, size_str, date_str, pathToPrint))

return output_str


def local_tree(path, config):
Expand Down
26 changes: 21 additions & 5 deletions smbclientng/modules/Find.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# Date created : 23 may 2024


import os
import ntpath
import re
from smbclientng.core.Module import Module
Expand Down Expand Up @@ -39,6 +40,7 @@ def parseArgs(self, arguments):

# Adding positional arguments
parser.add_argument("paths", metavar="PATH", type=str, nargs="*", default=[], help="The starting point(s) for the search.")
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).")
Expand All @@ -52,6 +54,7 @@ def parseArgs(self, arguments):
# 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.")
parser.add_argument("-o", "--outputfile", type=str, help="Write the names of the files found to the specified file.")

# Other options
parser.add_argument("-maxdepth", type=int, help="Descend at most levels (a non-negative integer) levels of directories below the command line arguments.")
Expand Down Expand Up @@ -189,17 +192,25 @@ def __find_callback(self, entry, fullpath, depth):
else:
self.smbSession.get_file(path=fullpath, keepRemotePath=True)
# Output formats
output_str = ""
if self.options.ls:
if entry.is_directory():
windows_ls_entry(entry=entry, config=self.config, pathToPrint=fullpath)
output_str = windows_ls_entry(entry=entry, config=self.config, pathToPrint=fullpath)
else:
windows_ls_entry(entry=entry, config=self.config, pathToPrint=fullpath)
output_str = windows_ls_entry(entry=entry, config=self.config, pathToPrint=fullpath)
else:
if entry.is_directory():
print("%s" % fullpath.replace(ntpath.sep, '/'))
output_str = ("%s" % fullpath.replace(ntpath.sep, '/'))
else:
print("%s" % fullpath.replace(ntpath.sep, '/'))

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')

if not self.options.quiet:
print(output_str)

return None

def run(self, arguments):
Expand All @@ -219,6 +230,11 @@ def run(self, arguments):

if self.options is not None:
# Entrypoint
if self.options.outputfile is not None:
if not os.path.exists(os.path.dirname(self.options.outputfile)):
os.makedirs(os.path.dirname(self.options.outputfile))
open(self.options.outputfile, 'w').close()

try:
next_directories_to_explore = []
for path in list(set(self.options.paths)):
Expand Down
Loading