smbclientng.core.InteractiveShell

   1#!/usr/bin/env python3
   2# -*- coding: utf-8 -*-
   3# File name          : InteractiveShell.py
   4# Author             : Podalirius (@podalirius_)
   5# Date created       : 23 may 2024
   6
   7
   8import charset_normalizer
   9import datetime
  10import impacket
  11from importlib import import_module
  12import ntpath
  13import os
  14import readline
  15import shutil
  16import shlex
  17import sys
  18import traceback
  19from rich.console import Console
  20from rich.table import Table
  21from rich.syntax import Syntax
  22from smbclientng.core.CommandCompleter import CommandCompleter
  23from smbclientng.core.utils import b_filesize, unix_permissions, windows_ls_entry, local_tree, resolve_local_files, resolve_remote_files
  24
  25
  26## Decorators
  27
  28def command_arguments_required(func):
  29    def wrapper(*args, **kwargs):
  30        self, arguments,command  = args[0], args[1], args[2]
  31        if len(arguments) != 0:
  32            return func(*args, **kwargs)
  33        else:
  34            self.commandCompleterObject.print_help(command=command)
  35            return None
  36    return wrapper
  37
  38def active_smb_connection_needed(func):
  39    def wrapper(*args, **kwargs):
  40        self, arguments,command  = args[0], args[1], args[2]
  41        #
  42        self.sessionsManager.current_session.ping_smb_session()
  43        if self.sessionsManager.current_session.connected:
  44            return func(*args, **kwargs)
  45        else:
  46            print("[!] SMB Session is disconnected.")
  47            return None
  48    return wrapper
  49
  50def smb_share_is_set(func):
  51    def wrapper(*args, **kwargs):
  52        self, arguments,command  = args[0], args[1], args[2]
  53        if self.sessionsManager.current_session.smb_share is not None:
  54            return func(*args, **kwargs)
  55        else:
  56            print("[!] You must open a share first, try the 'use <share>' command.")
  57            return None
  58    return wrapper
  59
  60
  61class InteractiveShell(object):
  62    """
  63    Class InteractiveShell is designed to manage the interactive command line interface for smbclient-ng.
  64    
  65    This class handles user input, executes commands, and manages the state of the SMB session. It provides
  66    a command line interface for users to interact with SMB shares, execute commands like directory listing,
  67    file transfer, and more.
  68
  69    Attributes:
  70        smbSession (SMBConnection): The active SMB connection session.
  71        debug (bool): Flag to enable or disable debug mode.
  72        smb_share (str): The current SMB share in use.
  73        smb_path (str): The current path within the SMB share.
  74        commandCompleterObject (CommandCompleter): Object to handle command completion and help generation.
  75
  76    Methods:
  77        __init__(self, smbSession, debug=False): Initializes the InteractiveShell with the given SMB session and debug mode.
  78        run(self): Starts the command line interface loop, processing user input until exit.
  79    """
  80
  81    running = True
  82    modules = {}
  83    
  84    def __init__(self, sessionsManager, config, logger):
  85        # Objects
  86        self.sessionsManager = sessionsManager
  87        self.config = config
  88        self.logger = logger
  89        # Internals
  90        self.commandCompleterObject = CommandCompleter(
  91            smbSession=self.sessionsManager.current_session,
  92            config=self.config,
  93            logger=self.logger,
  94        )
  95        readline.set_completer(self.commandCompleterObject.complete)
  96        readline.parse_and_bind("tab: complete")
  97        readline.set_completer_delims("\n")
  98        # Additional modules
  99        self.__load_modules()
 100
 101    def run(self):
 102        # Read commands from script file first
 103        if self.config.startup_script:
 104            f = open(self.config.startup_script, 'r')
 105            for line in f.readlines():
 106                try:
 107                    self.logger.print("%s%s" % (self.__prompt(), line.strip()))
 108                    readline.add_history(line.strip())
 109                    self.process_line(commandLine=line.strip())
 110                except KeyboardInterrupt as e:
 111                    self.logger.print()
 112
 113                except EOFError as e:
 114                    self.logger.print()
 115                    running = False
 116
 117                except Exception as err:
 118                    if self.config.debug:
 119                        traceback.print_exc()
 120                    self.logger.error(str(err))
 121
 122        # Then interactive console
 123        if not self.config.not_interactive:
 124            while self.running:
 125                try:
 126                    user_input = input(self.__prompt()).strip()
 127                    self.process_line(commandLine=user_input)
 128                except KeyboardInterrupt as e:
 129                    self.logger.print()
 130
 131                except EOFError as e:
 132                    self.logger.print()
 133                    running = False
 134
 135                except Exception as err:
 136                    if self.config.debug:
 137                        traceback.print_exc()
 138                    self.logger.error(str(err))
 139
 140    def process_line(self, commandLine):
 141        # Split and parse the commandLine
 142        tokens = shlex.split(commandLine)
 143        if len(tokens) == 0:
 144            command = ""
 145            arguments = []
 146        elif len(tokens) == 1:
 147            command = tokens[0].lower()
 148            arguments = []
 149        else:
 150            command = tokens[0].lower()
 151            arguments = tokens[1:]
 152        
 153        # Skip
 154        if command.strip() == "":
 155            pass
 156        # Execute the command
 157        elif command in self.commandCompleterObject.commands.keys():
 158
 159            # Exit the command line
 160            if command in ["exit", "quit"]:
 161                self.running = False
 162            
 163            # Display help
 164            elif command == "help":
 165                self.command_help(arguments, command)
 166
 167            # Cat the contents of a file
 168            elif command == "bat":
 169                self.command_bat(arguments, command)
 170
 171            # Cat the contents of a file
 172            elif command == "cat":
 173                self.command_cat(arguments, command)
 174
 175            # Closes the current SMB session
 176            elif command == "close":
 177                self.command_close(arguments, command)
 178                
 179            # Change directory in the current share
 180            elif command == "cd":
 181                self.command_cd(arguments, command)
 182            
 183            # debug
 184            elif command == "debug":
 185                self.command_debug(arguments, command)
 186
 187            # Get a file
 188            elif command == "get":
 189                self.command_get(arguments, command)
 190
 191            # SMB server info
 192            elif command == "info":
 193                self.command_info(arguments, command)
 194
 195            # List directory contents in a share
 196            elif command in ["ls", "dir"]:
 197                self.command_ls(arguments, command)
 198
 199            # Creates a new remote directory
 200            elif command == "mkdir":
 201                self.command_mkdir(arguments, command)
 202
 203            # Put a file
 204            elif command == "put":
 205                self.command_put(arguments, command)
 206
 207            # Shows the content of a local file
 208            elif command == "lcat":
 209                self.command_lcat(arguments, command)
 210
 211            # Changes the current local directory
 212            elif command == "lcd":
 213                self.command_lcd(arguments, command)
 214
 215            # Creates a copy of a local file
 216            elif command == "lcp":
 217                self.command_lcp(arguments, command)
 218
 219            # Pretty prints the content of a local file
 220            elif command == "lbat":
 221                self.command_lbat(arguments, command)
 222
 223            # Lists the contents of the current local directory
 224            elif command == "lls":
 225                self.command_lls(arguments, command)
 226
 227            # Creates a new local directory
 228            elif command == "lmkdir":
 229                self.command_lmkdir(arguments, command)
 230
 231            # Shows the current local directory
 232            elif command == "lpwd":
 233                self.command_lpwd(arguments, command)
 234
 235            # Renames a local file
 236            elif command == "lrename":
 237                self.command_lrename(arguments, command)
 238            
 239            # Removes a local file
 240            elif command == "lrm":
 241                self.command_lrm(arguments, command)
 242
 243            # Removes a local directory
 244            elif command == "lrmdir":
 245                self.command_lrmdir(arguments, command)
 246
 247            # Shows the current local directory
 248            elif command == "ltree":
 249                self.command_ltree(arguments, command)
 250
 251            # Modules
 252            elif command == "module":
 253                self.command_module(arguments, command)
 254
 255            # Creates a mount point of the remote share on the local machine
 256            elif command == "mount":
 257                self.command_mount(arguments, command)
 258
 259            # Reconnects the current SMB session
 260            elif command in ["connect", "reconnect"]:
 261                self.command_reconnect(arguments, command)
 262
 263            # Reset the TTY output
 264            elif command == "reset":
 265                self.command_reset(arguments, command)
 266
 267            # Removes a remote file
 268            elif command == "rm":
 269                self.command_rm(arguments, command)
 270                
 271            # Removes a remote directory
 272            elif command == "rmdir":
 273                self.command_rmdir(arguments, command)
 274
 275            # Sessions management
 276            elif command == "sessions":
 277                self.sessionsManager.process_command_line(arguments)
 278
 279            # List shares
 280            elif command == "sizeof":
 281                self.command_sizeof(arguments, command)
 282
 283            # List shares
 284            elif command == "shares":
 285                self.command_shares(arguments, command)
 286            
 287            # Displays a tree view of the CWD
 288            elif command == "tree":
 289                self.command_tree(arguments, command)
 290            
 291            # Use a share
 292            elif command == "use":
 293                self.command_use(arguments, command)
 294        
 295        # Fallback to unknown command   
 296        else:
 297            self.logger.print("Unknown command. Type \"help\" for help.")
 298
 299    # Commands ================================================================
 300
 301    def command_debug(self, arguments, command):
 302        try:
 303            self.logger.print("[debug] command    = '%s'" % command)
 304            self.logger.print("[debug] arguments  = %s" % arguments)
 305        except Exception as e:
 306            traceback.print_exc()
 307
 308    @command_arguments_required
 309    @active_smb_connection_needed
 310    @smb_share_is_set
 311    def command_bat(self, arguments, command):
 312        # Command arguments required   : Yes
 313        # Active SMB connection needed : Yes
 314        # SMB share needed             : Yes
 315
 316        # Parse wildcards
 317        files_and_directories = resolve_local_files(arguments)
 318
 319        for path_to_file in files_and_directories:
 320            if self.sessionsManager.current_session.path_isfile(pathFromRoot=path_to_file):
 321                # Read the file
 322                try:    
 323                    rawcontents = self.sessionsManager.current_session.read_file(path=path_to_file)
 324                    if rawcontents is not None:
 325                        encoding = charset_normalizer.detect(rawcontents)["encoding"]
 326                        if encoding is not None:
 327                            filecontent = rawcontents.decode(encoding).rstrip()
 328                            lexer = Syntax.guess_lexer(path=ntpath.basename(path_to_file), code=filecontent)
 329                            # Some trickery for the files undetected by the lexer
 330                            if lexer == "default":
 331                                if '<?xml' in filecontent:
 332                                    lexer = "xml"
 333                                elif '<html>' in filecontent:
 334                                    lexer = "html"
 335                            syntax = Syntax(code=filecontent, line_numbers=True, lexer=lexer)
 336                            if len(files_and_directories) > 1:
 337                                self.logger.print("\x1b[1;93m[>] %s\x1b[0m" % (path_to_file+' ').ljust(80,'='))
 338                            Console().print(syntax)
 339                        else:
 340                            self.logger.error("[!] Could not detect charset of '%s'." % path_to_file)
 341                except impacket.smbconnection.SessionError as e:
 342                    self.logger.error("[!] SMB Error: %s" % e)
 343
 344    @command_arguments_required
 345    @active_smb_connection_needed
 346    @smb_share_is_set
 347    def command_cd(self, arguments, command):
 348        # Command arguments required   : Yes
 349        # Active SMB connection needed : Yes
 350        # SMB share needed             : Yes
 351
 352        try:
 353            self.sessionsManager.current_session.set_cwd(path=arguments[0])
 354        except impacket.smbconnection.SessionError as e:
 355            self.logger.error("[!] SMB Error: %s" % e)
 356
 357    @command_arguments_required
 358    @active_smb_connection_needed
 359    @smb_share_is_set
 360    def command_cat(self, arguments, command):
 361        # Command arguments required   : Yes
 362        # Active SMB connection needed : Yes
 363        # SMB share needed             : Yes
 364
 365        # Parse wildcards
 366        files_and_directories = resolve_local_files(arguments)
 367
 368        for path_to_file in files_and_directories:
 369            if self.sessionsManager.current_session.path_isfile(pathFromRoot=path_to_file):
 370                # Read the file
 371                try:
 372                    rawcontents = self.sessionsManager.current_session.read_file(path=path_to_file)
 373                    if rawcontents is not None:
 374                        encoding = charset_normalizer.detect(rawcontents)["encoding"]
 375                        if encoding is not None:
 376                            filecontent = rawcontents.decode(encoding).rstrip()
 377                            if len(files_and_directories) > 1:
 378                                self.logger.print("\x1b[1;93m[>] %s\x1b[0m" % (path_to_file+' ').ljust(80,'='))
 379                            self.logger.print(filecontent)
 380                        else:
 381                            self.logger.error("[!] Could not detect charset of '%s'." % path_to_file)
 382                except impacket.smbconnection.SessionError as e:
 383                    self.logger.error("[!] SMB Error: %s" % e)
 384
 385    def command_close(self, arguments, command):
 386        # Command arguments required   : No
 387        # Active SMB connection needed : No
 388        # SMB share needed             : No
 389
 390        self.sessionsManager.current_session.ping_smb_session()
 391        if self.sessionsManager.current_session.connected:
 392            self.sessionsManager.current_session.close_smb_session()
 393
 394    @command_arguments_required
 395    @active_smb_connection_needed
 396    @smb_share_is_set
 397    def command_get(self, arguments, command):
 398        # Command arguments required   : Yes
 399        # Active SMB connection needed : Yes
 400        # SMB share needed             : Yes
 401
 402        is_recursive = False
 403        while '-r' in arguments:
 404            is_recursive = True
 405            arguments.remove('-r')
 406
 407        # Parse wildcards
 408        files_and_directories = resolve_remote_files(self.sessionsManager.current_session, arguments)
 409
 410        # 
 411        for remotepath in files_and_directories:
 412            try:
 413                if is_recursive and self.sessionsManager.current_session.path_isdir(remotepath):
 414                    # Get files recursively
 415                    self.sessionsManager.current_session.get_file_recursively(path=remotepath)
 416                else:
 417                    # Get this single file
 418                    self.sessionsManager.current_session.get_file(path=remotepath)
 419            except impacket.smbconnection.SessionError as e:
 420                self.logger.error("[!] SMB Error: %s" % e)
 421
 422    def command_help(self, arguments, command):
 423        # Command arguments required   : No
 424        # Active SMB connection needed : No
 425        # SMB share needed             : No
 426
 427        if len(arguments) != 0:
 428            self.commandCompleterObject.print_help(command=arguments[0])
 429        else:
 430            self.commandCompleterObject.print_help(command=None)
 431
 432    @active_smb_connection_needed
 433    def command_info(self, arguments, command):
 434        # Command arguments required   : No
 435        # Active SMB connection needed : Yes
 436        # SMB share needed             : No
 437
 438        print_server_info = False
 439        print_share_info = False
 440        if len(arguments) != 0:
 441            print_server_info = (arguments[0].lower() == "server")
 442            print_share_info = (arguments[0].lower() == "share")
 443        else:
 444            print_server_info = True
 445            print_share_info = True
 446
 447        try:
 448            self.sessionsManager.current_session.info(
 449                share=print_share_info,
 450                server=print_server_info
 451            )
 452        except impacket.smbconnection.SessionError as e:
 453            self.logger.error("[!] SMB Error: %s" % e)
 454
 455    @command_arguments_required
 456    def command_lbat(self, arguments, command):
 457        # Command arguments required   : Yes
 458        # Active SMB connection needed : No
 459        # SMB share needed             : No
 460
 461        # Parse wildcards
 462        files_and_directories = resolve_remote_files(self.sessionsManager.current_session, arguments)
 463
 464        for path_to_file in files_and_directories:
 465            # Read the file
 466            try:
 467                if os.path.exists(path=path_to_file):
 468                    f = open(path_to_file, 'rb')
 469                    rawcontents = f.read()
 470                    #
 471                    if rawcontents is not None:
 472                        encoding = charset_normalizer.detect(rawcontents)["encoding"]
 473                        if encoding is not None:
 474                            filecontent = rawcontents.decode(encoding).rstrip()
 475                            lexer = Syntax.guess_lexer(path=ntpath.basename(path_to_file), code=filecontent)
 476                            # Some trickery for the files undetected by the lexer
 477                            if lexer == "default":
 478                                if '<?xml' in filecontent:
 479                                    lexer = "xml"
 480                                elif '<html>' in filecontent:
 481                                    lexer = "html"
 482                            syntax = Syntax(code=filecontent, line_numbers=True, lexer=lexer)
 483                            if len(files_and_directories) > 1:
 484                                self.logger.print("\x1b[1;93m[>] %s\x1b[0m" % (path_to_file+' ').ljust(80,'='))
 485                            Console().print(syntax)
 486                        else:
 487                            self.logger.error("[!] Could not detect charset of '%s'." % path_to_file)
 488                else:
 489                    self.logger.error("[!] Local file '%s' does not exist." % path_to_file)
 490            except impacket.smbconnection.SessionError as e:
 491                self.logger.error("[!] SMB Error: %s" % e)
 492
 493    @command_arguments_required
 494    def command_lcat(self, arguments, command):
 495        # Command arguments required   : Yes
 496        # Active SMB connection needed : No
 497        # SMB share needed             : No
 498
 499        # Parse wildcards
 500        files_and_directories = resolve_remote_files(self.sessionsManager.current_session, arguments)
 501
 502        for path_to_file in files_and_directories:
 503            # Read the file 
 504            try:
 505                if os.path.exists(path=path_to_file):
 506                    f = open(path_to_file, 'rb')
 507                    rawcontents = f.read()
 508                    #
 509                    if rawcontents is not None:
 510                        encoding = charset_normalizer.detect(rawcontents)["encoding"]
 511                        if encoding is not None:
 512                            filecontent = rawcontents.decode(encoding).rstrip()
 513                            if len(files_and_directories) > 1:
 514                                self.logger.print("\x1b[1;93m[>] %s\x1b[0m" % (path_to_file+' ').ljust(80,'='))
 515                            self.logger.print(filecontent)
 516                        else:
 517                            self.logger.error("[!] Could not detect charset of '%s'." % path_to_file)
 518                else:
 519                    self.logger.error("[!] Local file '%s' does not exist." % path_to_file)
 520            except impacket.smbconnection.SessionError as e:
 521                self.logger.error("[!] SMB Error: %s" % e)
 522
 523    @command_arguments_required
 524    def command_lcd(self, arguments, command):
 525        # Command arguments required   : Yes
 526        # Active SMB connection needed : No
 527        # SMB share needed             : No
 528        
 529        path = arguments[0]
 530
 531        if os.path.exists(path=path):
 532            if os.path.isdir(s=path):
 533                os.chdir(path=path)
 534            else:
 535                self.logger.error("Path '%s' is not a directory." % path)
 536        else:
 537            self.logger.error("Directory '%s' does not exists." % path)
 538
 539    @command_arguments_required
 540    def command_lcp(self, arguments, command):
 541        # Command arguments required   : Yes
 542        # Active SMB connection needed : No
 543        # SMB share needed             : No
 544
 545        if len(arguments) == 2:
 546            src_path = arguments[0]
 547            dst_path = arguments[1]
 548            if os.path.exists(path=src_path):
 549                try:
 550                    shutil.copyfile(src=src_path, dst=dst_path)
 551                except shutil.SameFileError as err:
 552                    self.logger.error("[!] Error: %s" % err)
 553            else:
 554                self.logger.error("[!] File '%s' does not exists." % src_path)
 555        else:
 556            self.commandCompleterObject.print_help(command=command)
 557
 558    def command_lls(self, arguments, command):
 559        # Command arguments required   : No
 560        # Active SMB connection needed : No
 561        # SMB share needed             : No
 562
 563        if len(arguments) == 0:
 564            arguments = ['.']
 565        else:
 566            arguments = resolve_local_files(arguments)
 567
 568        for path in arguments:
 569            if len(arguments) > 1:
 570                self.logger.print("%s:" % path)
 571            # lls <directory>
 572            if os.path.isdir(path):
 573                directory_contents = os.listdir(path=path)
 574                for entryname in sorted(directory_contents):
 575                    path_to_file = path + os.path.sep + entryname
 576                    rights_str = unix_permissions(path_to_file)
 577                    size_str = b_filesize(os.path.getsize(filename=path_to_file))
 578                    date_str = datetime.datetime.fromtimestamp(os.path.getmtime(filename=path_to_file)).strftime("%Y-%m-%d %H:%M")
 579
 580                    if os.path.isdir(s=entryname):
 581                        if self.config.no_colors:
 582                            self.logger.print("%s %10s  %s  %s%s" % (rights_str, size_str, date_str, entryname, os.path.sep))
 583                        else:
 584                            self.logger.print("%s %10s  %s  \x1b[1;96m%s\x1b[0m%s" % (rights_str, size_str, date_str, entryname, os.path.sep))
 585                    else:
 586                        if self.config.no_colors:
 587                            self.logger.print("%s %10s  %s  %s" % (rights_str, size_str, date_str, entryname))
 588                        else:
 589                            self.logger.print("%s %10s  %s  \x1b[1m%s\x1b[0m" % (rights_str, size_str, date_str, entryname))
 590            # lls <file>
 591            elif os.path.isfile(path):
 592                rights_str = unix_permissions(path)
 593                size_str = b_filesize(os.path.getsize(filename=path))
 594                date_str = datetime.datetime.fromtimestamp(os.path.getmtime(filename=path)).strftime("%Y-%m-%d %H:%M")
 595                if self.config.no_colors:
 596                    self.logger.print("%s %10s  %s  %s" % (rights_str, size_str, date_str, os.path.basename(path)))
 597                else:
 598                    self.logger.print("%s %10s  %s  \x1b[1m%s\x1b[0m" % (rights_str, size_str, date_str, os.path.basename(path))) 
 599            
 600            if len(arguments) > 1:
 601                self.logger.print()
 602
 603    @command_arguments_required
 604    def command_lmkdir(self, arguments, command):
 605        # Command arguments required   : Yes
 606        # Active SMB connection needed : No
 607        # SMB share needed             : No
 608
 609        for path in arguments:
 610            if os.path.sep in path:
 611                path = path.strip(os.path.sep).split(os.path.sep)
 612            else:
 613                path = [path]
 614
 615            # Create each dir in the path
 616            for depth in range(1, len(path)+1):
 617                tmp_path = os.path.sep.join(path[:depth])
 618                if not os.path.exists(tmp_path):
 619                    os.mkdir(path=tmp_path)
 620
 621    def command_lpwd(self, arguments, command):
 622        # Command arguments required   : No
 623        # Active SMB connection needed : No
 624        # SMB share needed             : No
 625
 626        self.logger.print(os.getcwd())
 627
 628    @command_arguments_required
 629    def command_lrename(self, arguments, command):
 630        # Command arguments required   : Yes
 631        # Active SMB connection needed : No
 632        # SMB share needed             : No
 633
 634        if len(arguments) == 2:
 635            os.rename(src=arguments[0], dst=arguments[1])
 636        else:
 637            self.commandCompleterObject.print_help(command=command)
 638
 639    @command_arguments_required
 640    def command_lrm(self, arguments, command):
 641        # Command arguments required   : Yes
 642        # Active SMB connection needed : No
 643        # SMB share needed             : No
 644
 645        path = arguments[0]
 646
 647        if os.path.exists(path):
 648            if not os.path.isdir(s=path):
 649                try:
 650                    os.remove(path=path)
 651                except Exception as e:
 652                    self.logger.error("Error removing file '%s' : %s" % path)
 653            else:
 654                self.logger.error("Cannot delete '%s'. It is a directory, use 'lrmdir <directory>' instead." % path)
 655        else:
 656            self.logger.error("Path '%s' does not exist." % path)
 657
 658    @command_arguments_required
 659    def command_lrmdir(self, arguments, command):
 660        # Command arguments required   : Yes
 661        # Active SMB connection needed : No
 662        # SMB share needed             : No
 663
 664        if len(arguments) == 0:
 665            path = '.'
 666        else:
 667            path = arguments[0]
 668
 669        if os.path.exists(path):
 670            if os.path.isdir(s=path):
 671                try:
 672                    shutil.rmtree(path=path)
 673                except Exception as e:
 674                    self.logger.error("Error removing directory '%s' : %s" % path)
 675            else:
 676                self.logger.error("Cannot delete '%s'. It is a file, use 'lrm <file>' instead." % path)
 677        else:
 678            self.logger.error("Path '%s' does not exist." % path)
 679
 680    def command_ltree(self, arguments, command):
 681        # Command arguments required   : No
 682        # Active SMB connection needed : No
 683        # SMB share needed             : No
 684
 685        if len(arguments) == 0:
 686            path = '.'
 687        else:
 688            path = arguments[0]
 689
 690        if len(arguments) == 0:
 691            local_tree(path='.', config=self.config)
 692        else:
 693            local_tree(path=path, config=self.config)
 694
 695    @active_smb_connection_needed
 696    @smb_share_is_set
 697    def command_ls(self, arguments, command):
 698        # Command arguments required   : No
 699        # Active SMB connection needed : Yes
 700        # SMB share needed             : Yes
 701
 702        if len(arguments) == 0:
 703            arguments = ['.']
 704        else:
 705            arguments = resolve_remote_files(self.sessionsManager.current_session, arguments)
 706
 707        for path in arguments:
 708            if len(arguments) > 1:
 709                self.logger.print("%s:" % path)
 710
 711            if self.sessionsManager.current_session.path_isdir(pathFromRoot=path):
 712                # Read the files
 713                directory_contents = self.sessionsManager.current_session.list_contents(path=path)
 714            else:
 715                entry = self.sessionsManager.current_session.get_entry(path=path)
 716                if entry is not None:
 717                    directory_contents = {entry.get_longname(): entry}
 718                else:
 719                    directory_contents = {}
 720
 721            for longname in sorted(directory_contents.keys(), key=lambda x:x.lower()):
 722                windows_ls_entry(directory_contents[longname], self.config)
 723
 724            if len(arguments) > 1:
 725                self.logger.print()
 726            
 727    @command_arguments_required
 728    @active_smb_connection_needed
 729    @smb_share_is_set
 730    def command_mkdir(self, arguments, command):
 731        # Command arguments required   : Yes
 732        # Active SMB connection needed : Yes
 733        # SMB share needed             : Yes
 734
 735        self.sessionsManager.current_session.mkdir(path=arguments[0])
 736
 737    @command_arguments_required
 738    @active_smb_connection_needed
 739    @smb_share_is_set
 740    def command_module(self, arguments, command):
 741        module_name = arguments[0]
 742
 743        if module_name in self.modules.keys():
 744            module = self.modules[module_name](self.sessionsManager.current_session, self.config, self.logger)
 745            arguments_string = ' '.join(arguments[1:])
 746            module.run(arguments_string)
 747        else:
 748            self.logger.error("Module '%s' does not exist." % module_name)
 749
 750    @command_arguments_required
 751    @active_smb_connection_needed
 752    @smb_share_is_set
 753    def command_mount(self, arguments, command):
 754        # Command arguments required   : Yes
 755        # Active SMB connection needed : Yes
 756        # SMB share needed             : Yes
 757
 758        if len(arguments) == 2:
 759            remote_path = arguments[0]
 760            if not remote_path.startswith(ntpath.sep):
 761                remote_path = self.sessionsManager.current_session.smb_cwd + ntpath.sep + remote_path
 762
 763            local_mount_point = arguments[1]
 764
 765            self.logger.debug("Trying to mount remote '%s' onto local '%s'" % (remote_path, local_mount_point))
 766
 767            try:
 768                self.sessionsManager.current_session.mount(local_mount_point, remote_path)
 769            except (impacket.smbconnection.SessionError, impacket.smb3.SessionError) as e:
 770                self.sessionsManager.current_session.umount(local_mount_point)
 771        else:
 772            self.commandCompleterObject.print_help(command=command)
 773
 774    @command_arguments_required
 775    @active_smb_connection_needed
 776    @smb_share_is_set
 777    def command_put(self, arguments, command):
 778        # Command arguments required   : Yes
 779        # Active SMB connection needed : Yes
 780        # SMB share needed             : Yes
 781        
 782        is_recursive = False
 783        while '-r' in arguments:
 784            is_recursive = True
 785            arguments.remove('-r')
 786
 787        # Parse wildcards
 788        files_and_directories = resolve_local_files(arguments)
 789
 790        # 
 791        for localpath in files_and_directories:
 792            try:
 793                self.logger.print(localpath)
 794                if is_recursive and os.path.isdir(s=localpath):
 795                    # Put files recursively
 796                    self.sessionsManager.current_session.put_file_recursively(localpath=localpath)
 797                else:
 798                    # Put this single file
 799                    self.sessionsManager.current_session.put_file(localpath=localpath)
 800            except impacket.smbconnection.SessionError as e:
 801                self.logger.error("[!] SMB Error: %s" % e)
 802
 803    def command_reconnect(self, arguments, command):
 804        # Command arguments required   : No
 805        # Active SMB connection needed : No
 806        # SMB share needed             : No
 807
 808        self.sessionsManager.current_session.ping_smb_session()
 809        if self.sessionsManager.current_session.connected:
 810            self.sessionsManager.current_session.close_smb_session()
 811            self.sessionsManager.current_session.init_smb_session()
 812        else:
 813            self.sessionsManager.current_session.init_smb_session()
 814
 815    def command_reset(self, arguments, command):
 816        # Command arguments required   : No
 817        # Active SMB connection needed : No
 818        # SMB share needed             : No
 819        sys.stdout.write('\x1b[?25h') # Sets the cursor to on
 820        sys.stdout.write('\x1b[v')  
 821        sys.stdout.write('\x1b[o') # Reset
 822        sys.stdout.flush()
 823
 824    @command_arguments_required
 825    @active_smb_connection_needed
 826    @smb_share_is_set
 827    def command_rm(self, arguments, command):
 828        # Command arguments required   : Yes
 829        # Active SMB connection needed : Yes
 830        # SMB share needed             : Yes
 831
 832        for path_to_file in arguments:
 833            # Wildcard
 834            if '*' in path_to_file:
 835                self.sessionsManager.current_session.rm(path=path_to_file)
 836            # File
 837            elif self.sessionsManager.current_session.path_exists(path_to_file):
 838                if self.sessionsManager.current_session.path_isfile(path_to_file):
 839                    try:
 840                        self.sessionsManager.current_session.rm(path=path_to_file)
 841                    except Exception as e:
 842                        self.logger.error("Error removing file '%s' : %s" % path_to_file)
 843                else:
 844                    self.logger.error("Cannot delete '%s': This is a directory, use 'rmdir <directory>' instead." % path_to_file)
 845            # File does not exist
 846            else:
 847                self.logger.error("Remote file '%s' does not exist." % path_to_file)
 848
 849    @command_arguments_required
 850    @active_smb_connection_needed
 851    @smb_share_is_set
 852    def command_rmdir(self, arguments, command):
 853        # Command arguments required   : Yes
 854        # Active SMB connection needed : Yes
 855        # SMB share needed             : Yes
 856
 857        for path_to_directory in arguments:
 858            if self.sessionsManager.current_session.path_exists(path_to_directory):
 859                if self.sessionsManager.current_session.path_isdir(path_to_directory):
 860                    try:
 861                        self.sessionsManager.current_session.rmdir(path=path_to_directory)
 862                    except Exception as e:
 863                        self.logger.error("Error removing directory '%s' : %s" % path_to_directory)
 864                else:
 865                    self.logger.error("Cannot delete '%s': This is a file, use 'rm <file>' instead." % path_to_directory)
 866            else:
 867                self.logger.error("Remote directory '%s' does not exist." % path_to_directory)
 868
 869    @active_smb_connection_needed
 870    @smb_share_is_set
 871    def command_sizeof(self, arguments, command):
 872        # Command arguments required   : Yes
 873        # Active SMB connection needed : Yes
 874        # SMB share needed             : Yes
 875
 876        class RecursiveSizeOfPrint(object):
 877            def __init__(self, entry, sessionsManager, config, logger):
 878                self.entry = entry
 879                self.config = config
 880                self.logger = logger
 881                self.sessionsManager = sessionsManager
 882                self.size = 0
 883            
 884            def update(self, entry, fullpath, depth):
 885                self.size += entry.get_filesize()
 886                self.print(end='\r')
 887            
 888            def print(self, end='\n'):
 889                # Directory
 890                if self.entry.is_directory():
 891                    if self.config.no_colors:
 892                        path = "%s\\" % self.entry.get_longname()
 893                    else:
 894                        path = "\x1b[1;96m%s\x1b[0m\\" % self.entry.get_longname()
 895                # File
 896                else:
 897                    if self.config.no_colors:
 898                        path = "%s" % self.entry.get_longname()
 899                    else:
 900                        path = "\x1b[1m%s\x1b[0m" % self.entry.get_longname()
 901                self.logger.print("%10s  %s" % (b_filesize(self.size), path), end=end)
 902
 903        entries = []
 904        if len(arguments) == 0:
 905            entries = self.sessionsManager.current_session.list_contents()
 906            entries = [entry for name, entry in entries.items() if name not in ['.', '..']]
 907        else:
 908            entry = self.sessionsManager.current_session.get_entry(path=' '.join(arguments))
 909            entries = []
 910            if entry is not None:
 911                entries = [entry]
 912            else:
 913                self.logger.print("[!] Path '%s' does not exist." % ' '.join(arguments))
 914
 915        total = 0
 916        for entry in entries:
 917            rsop = RecursiveSizeOfPrint(
 918                entry=entry, 
 919                sessionsManager=self.sessionsManager, 
 920                config=self.config,
 921                logger=self.logger
 922            )
 923            # Directory
 924            if entry.is_directory():
 925                self.sessionsManager.current_session.find(
 926                    paths=[entry.get_longname()],
 927                    callback=rsop.update
 928                )
 929            # File
 930            else:
 931                rsop.update(entry=entry, fullpath=entry.get_longname(), depth=0)
 932            # Close the print
 933            rsop.print()
 934            total += rsop.size
 935        
 936        if len(entries) > 1:
 937            self.logger.print("──────────────────────")
 938            self.logger.print("     total  %s" % b_filesize(total))
 939
 940    @active_smb_connection_needed
 941    def command_shares(self, arguments, command):
 942        # Command arguments required   : No
 943        # Active SMB connection needed : Yes
 944        # SMB share needed             : No
 945
 946        do_check_rights = False
 947        if len(arguments) != 0:
 948            if arguments[0] == "rights":
 949                do_check_rights = True
 950
 951        shares = self.sessionsManager.current_session.list_shares()
 952        if len(shares.keys()) != 0:
 953            table = Table(title=None)
 954            table.add_column("Share")
 955            table.add_column("Visibility")
 956            table.add_column("Type")
 957            table.add_column("Description", justify="left")
 958            if do_check_rights:
 959                table.add_column("Rights")
 960
 961            for sharename in sorted(shares.keys()):
 962                types = ', '.join([s.replace("STYPE_","") for s in shares[sharename]["type"]])
 963
 964                is_hidden = bool(sharename.endswith('$'))
 965                if is_hidden:
 966                    str_hidden = "[bold bright_blue]Hidden[/bold bright_blue]"
 967                    str_sharename = "[bold bright_blue]" + shares[sharename]["name"] + "[/bold bright_blue]"
 968                    str_types = "[bold bright_blue]" + types + "[/bold bright_blue]"
 969                    str_comment = "[bold bright_blue]" + shares[sharename]["comment"] + "[/bold bright_blue]"
 970                else:
 971                    str_hidden = "[bold bright_yellow]Visible[/bold bright_yellow]"
 972                    str_sharename = "[bold bright_yellow]" + shares[sharename]["name"] + "[/bold bright_yellow]"
 973                    str_types = "[bold bright_yellow]" + types + "[/bold bright_yellow]"
 974                    str_comment = "[bold bright_yellow]" + shares[sharename]["comment"] + "[/bold bright_yellow]"
 975
 976                if do_check_rights:
 977                    access_rights = self.sessionsManager.current_session.test_rights(sharename=shares[sharename]["name"])
 978                    str_access_rights = "[bold yellow]NO ACCESS[/bold yellow]"
 979                    if access_rights["readable"] and access_rights["writable"]:
 980                        str_access_rights = "[bold green]READ[/bold green], [bold red]WRITE[/bold red]"
 981                    elif access_rights["readable"]:
 982                        str_access_rights = "[bold green]READ[/bold green]"
 983                    elif access_rights["writable"]:
 984                        # Without READ?? This should not happen IMHO
 985                        str_access_rights = "[bold red]WRITE[/bold red]"
 986                    else:
 987                        str_access_rights = "[bold yellow]NO ACCESS[/bold yellow]"
 988
 989                if do_check_rights:
 990                    table.add_row(str_sharename, str_hidden, str_types, str_comment, str_access_rights)
 991                else:
 992                    table.add_row(str_sharename, str_hidden, str_types, str_comment)
 993
 994            Console().print(table)
 995        else:
 996            self.logger.error("No share served on '%s'" % self.sessionsManager.current_session.host)
 997
 998    @active_smb_connection_needed
 999    @smb_share_is_set
1000    def command_tree(self, arguments, command):
1001        # Command arguments required   : No
1002        # Active SMB connection needed : Yes
1003        # SMB share needed             : Yes
1004
1005        if len(arguments) == 0:
1006            self.sessionsManager.current_session.tree(path='.')
1007        else:
1008            self.sessionsManager.current_session.tree(path=arguments[0])
1009
1010    @command_arguments_required
1011    @active_smb_connection_needed
1012    @smb_share_is_set
1013    def command_umount(self, arguments, command):
1014        # Command arguments required   : Yes
1015        # Active SMB connection needed : Yes
1016        # SMB share needed             : Yes
1017
1018        local_mount_point = arguments[0]
1019
1020        self.logger.debug("Trying to unmount local mount point '%s'" % (local_mount_point))
1021        
1022        self.sessionsManager.current_session.umount(local_mount_point)
1023        
1024    @command_arguments_required
1025    @active_smb_connection_needed
1026    def command_use(self, arguments, command):
1027        # Command arguments required   : Yes
1028        # Active SMB connection needed : Yes
1029        # SMB share needed             : No
1030
1031        sharename = arguments[0]
1032
1033        # Reload the list of shares
1034        shares = self.sessionsManager.current_session.list_shares()
1035        shares = [s.lower() for s in shares.keys()]
1036
1037        if sharename.lower() in shares:
1038            self.sessionsManager.current_session.set_share(sharename)
1039        else:
1040            self.logger.error("No share named '%s' on '%s'" % (sharename, self.sessionsManager.current_session.host))
1041
1042    # Private functions =======================================================
1043
1044    def __load_modules(self):
1045        """
1046        Dynamically loads all Python modules from the 'modules' directory and stores them in the 'modules' dictionary.
1047        Each module is expected to be a Python file that contains a class with the same name as the file (minus the .py extension).
1048        The class must have at least two attributes: 'name' and 'description'.
1049        
1050        This method clears any previously loaded modules, constructs the path to the modules directory, and iterates over
1051        each file in that directory. If the file is a Python file (ends with .py and is not '__init__.py'), it attempts to
1052        import the module and access the class within it to add to the 'modules' dictionary.
1053        
1054        If debug mode is enabled in the configuration, it prints debug information about the loading process and the loaded modules.
1055        """
1056
1057        self.modules.clear()
1058
1059        modules_dir = os.path.normpath(os.path.dirname(__file__) + os.path.sep + ".." + os.path.sep + "modules")
1060        self.logger.debug("Loading modules from %s ..." % modules_dir)
1061        sys.path.extend([modules_dir])
1062
1063        for file in os.listdir(modules_dir):
1064            filepath = os.path.normpath(modules_dir + os.path.sep + file)
1065            if file.endswith('.py'):
1066                if os.path.isfile(filepath) and file not in ["__init__.py"]:
1067                    try:
1068                        module_file = import_module('smbclientng.modules.%s' % (file[:-3]))
1069                        module = module_file.__getattribute__(file[:-3])
1070                        self.modules[module.name.lower()] = module
1071                    except AttributeError as e:
1072                        pass
1073
1074        if self.config.debug:
1075            if len(self.modules.keys()) == 0:
1076                self.logger.debug("Loaded 0 modules.")
1077            elif len(self.modules.keys()) == 1:
1078                self.logger.debug("Loaded 1 module:")
1079            else:
1080                self.logger.debug("Loaded %d modules:" % len(self.modules.keys()))
1081            for modulename in sorted(self.modules.keys()):
1082                self.logger.debug("%s : \"%s\" (%s)" % (self.modules[modulename].name, self.modules[modulename].description, self.modules[modulename]))
1083
1084        if self.commandCompleterObject is not None:
1085            self.commandCompleterObject.commands["module"]["subcommands"] = list(self.modules.keys())
1086
1087    def __prompt(self):
1088        """
1089        Prints the command prompt for the interactive shell.
1090
1091        This method constructs and returns the command prompt string based on the current state of the SMB session.
1092        The prompt indicates the connection status with a visual symbol and displays the current working directory
1093        or the SMB share path. The prompt appearance changes based on whether colors are enabled in the configuration.
1094
1095        Returns:
1096            str: The formatted command prompt string.
1097        """
1098
1099        # A session exists
1100        if self.sessionsManager.current_session is not None:
1101            # Check if the session is still active
1102            self.sessionsManager.current_session.ping_smb_session()
1103            if self.sessionsManager.current_session.connected:
1104                if self.config.no_colors:
1105                    connected_dot = "[v]"
1106                else:
1107                    connected_dot = "\x1b[1;92m⏺\x1b[0m"
1108            else:
1109                if self.config.no_colors:
1110                    connected_dot = "[x]"
1111                else:
1112                    connected_dot = "\x1b[1;91m⏺\x1b[0m"
1113            
1114            # Session ID if 
1115            session_prompt = ""
1116            if len(self.sessionsManager.sessions.keys()) >= 2:
1117                session_prompt = "[#%d]" % self.sessionsManager.current_session_id
1118
1119            # No share set yet
1120            if self.sessionsManager.current_session.smb_share is None:
1121                str_path = "\\\\%s\\" % self.sessionsManager.current_session.host
1122            # A share is set
1123            else:
1124                if len(self.sessionsManager.current_session.smb_cwd) == 0:
1125                    current_path = ""
1126                else:
1127                    current_path = self.sessionsManager.current_session.smb_cwd.strip(ntpath.sep) + ntpath.sep
1128                
1129                str_path = "\\\\%s\\%s\\%s" % (self.sessionsManager.current_session.host, self.sessionsManager.current_session.smb_share, current_path)
1130        # No active session
1131        else:
1132            connected_dot = ""
1133            session_prompt = ""
1134            str_path = "No active session"
1135
1136        # Build final prompt string
1137        if self.config.no_colors:
1138            str_prompt = "%s%s[%s]> " % (connected_dot, session_prompt, str_path)
1139        else:
1140            str_prompt = "%s%s[\x1b[1;94m%s\x1b[0m]> " % (connected_dot, session_prompt, str_path)
1141
1142        return str_prompt
def command_arguments_required(func):
29def command_arguments_required(func):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
37    return wrapper
def active_smb_connection_needed(func):
39def active_smb_connection_needed(func):
40    def wrapper(*args, **kwargs):
41        self, arguments,command  = args[0], args[1], args[2]
42        #
43        self.sessionsManager.current_session.ping_smb_session()
44        if self.sessionsManager.current_session.connected:
45            return func(*args, **kwargs)
46        else:
47            print("[!] SMB Session is disconnected.")
48            return None
49    return wrapper
def smb_share_is_set(func):
51def smb_share_is_set(func):
52    def wrapper(*args, **kwargs):
53        self, arguments,command  = args[0], args[1], args[2]
54        if self.sessionsManager.current_session.smb_share is not None:
55            return func(*args, **kwargs)
56        else:
57            print("[!] You must open a share first, try the 'use <share>' command.")
58            return None
59    return wrapper
class InteractiveShell:
  62class InteractiveShell(object):
  63    """
  64    Class InteractiveShell is designed to manage the interactive command line interface for smbclient-ng.
  65    
  66    This class handles user input, executes commands, and manages the state of the SMB session. It provides
  67    a command line interface for users to interact with SMB shares, execute commands like directory listing,
  68    file transfer, and more.
  69
  70    Attributes:
  71        smbSession (SMBConnection): The active SMB connection session.
  72        debug (bool): Flag to enable or disable debug mode.
  73        smb_share (str): The current SMB share in use.
  74        smb_path (str): The current path within the SMB share.
  75        commandCompleterObject (CommandCompleter): Object to handle command completion and help generation.
  76
  77    Methods:
  78        __init__(self, smbSession, debug=False): Initializes the InteractiveShell with the given SMB session and debug mode.
  79        run(self): Starts the command line interface loop, processing user input until exit.
  80    """
  81
  82    running = True
  83    modules = {}
  84    
  85    def __init__(self, sessionsManager, config, logger):
  86        # Objects
  87        self.sessionsManager = sessionsManager
  88        self.config = config
  89        self.logger = logger
  90        # Internals
  91        self.commandCompleterObject = CommandCompleter(
  92            smbSession=self.sessionsManager.current_session,
  93            config=self.config,
  94            logger=self.logger,
  95        )
  96        readline.set_completer(self.commandCompleterObject.complete)
  97        readline.parse_and_bind("tab: complete")
  98        readline.set_completer_delims("\n")
  99        # Additional modules
 100        self.__load_modules()
 101
 102    def run(self):
 103        # Read commands from script file first
 104        if self.config.startup_script:
 105            f = open(self.config.startup_script, 'r')
 106            for line in f.readlines():
 107                try:
 108                    self.logger.print("%s%s" % (self.__prompt(), line.strip()))
 109                    readline.add_history(line.strip())
 110                    self.process_line(commandLine=line.strip())
 111                except KeyboardInterrupt as e:
 112                    self.logger.print()
 113
 114                except EOFError as e:
 115                    self.logger.print()
 116                    running = False
 117
 118                except Exception as err:
 119                    if self.config.debug:
 120                        traceback.print_exc()
 121                    self.logger.error(str(err))
 122
 123        # Then interactive console
 124        if not self.config.not_interactive:
 125            while self.running:
 126                try:
 127                    user_input = input(self.__prompt()).strip()
 128                    self.process_line(commandLine=user_input)
 129                except KeyboardInterrupt as e:
 130                    self.logger.print()
 131
 132                except EOFError as e:
 133                    self.logger.print()
 134                    running = False
 135
 136                except Exception as err:
 137                    if self.config.debug:
 138                        traceback.print_exc()
 139                    self.logger.error(str(err))
 140
 141    def process_line(self, commandLine):
 142        # Split and parse the commandLine
 143        tokens = shlex.split(commandLine)
 144        if len(tokens) == 0:
 145            command = ""
 146            arguments = []
 147        elif len(tokens) == 1:
 148            command = tokens[0].lower()
 149            arguments = []
 150        else:
 151            command = tokens[0].lower()
 152            arguments = tokens[1:]
 153        
 154        # Skip
 155        if command.strip() == "":
 156            pass
 157        # Execute the command
 158        elif command in self.commandCompleterObject.commands.keys():
 159
 160            # Exit the command line
 161            if command in ["exit", "quit"]:
 162                self.running = False
 163            
 164            # Display help
 165            elif command == "help":
 166                self.command_help(arguments, command)
 167
 168            # Cat the contents of a file
 169            elif command == "bat":
 170                self.command_bat(arguments, command)
 171
 172            # Cat the contents of a file
 173            elif command == "cat":
 174                self.command_cat(arguments, command)
 175
 176            # Closes the current SMB session
 177            elif command == "close":
 178                self.command_close(arguments, command)
 179                
 180            # Change directory in the current share
 181            elif command == "cd":
 182                self.command_cd(arguments, command)
 183            
 184            # debug
 185            elif command == "debug":
 186                self.command_debug(arguments, command)
 187
 188            # Get a file
 189            elif command == "get":
 190                self.command_get(arguments, command)
 191
 192            # SMB server info
 193            elif command == "info":
 194                self.command_info(arguments, command)
 195
 196            # List directory contents in a share
 197            elif command in ["ls", "dir"]:
 198                self.command_ls(arguments, command)
 199
 200            # Creates a new remote directory
 201            elif command == "mkdir":
 202                self.command_mkdir(arguments, command)
 203
 204            # Put a file
 205            elif command == "put":
 206                self.command_put(arguments, command)
 207
 208            # Shows the content of a local file
 209            elif command == "lcat":
 210                self.command_lcat(arguments, command)
 211
 212            # Changes the current local directory
 213            elif command == "lcd":
 214                self.command_lcd(arguments, command)
 215
 216            # Creates a copy of a local file
 217            elif command == "lcp":
 218                self.command_lcp(arguments, command)
 219
 220            # Pretty prints the content of a local file
 221            elif command == "lbat":
 222                self.command_lbat(arguments, command)
 223
 224            # Lists the contents of the current local directory
 225            elif command == "lls":
 226                self.command_lls(arguments, command)
 227
 228            # Creates a new local directory
 229            elif command == "lmkdir":
 230                self.command_lmkdir(arguments, command)
 231
 232            # Shows the current local directory
 233            elif command == "lpwd":
 234                self.command_lpwd(arguments, command)
 235
 236            # Renames a local file
 237            elif command == "lrename":
 238                self.command_lrename(arguments, command)
 239            
 240            # Removes a local file
 241            elif command == "lrm":
 242                self.command_lrm(arguments, command)
 243
 244            # Removes a local directory
 245            elif command == "lrmdir":
 246                self.command_lrmdir(arguments, command)
 247
 248            # Shows the current local directory
 249            elif command == "ltree":
 250                self.command_ltree(arguments, command)
 251
 252            # Modules
 253            elif command == "module":
 254                self.command_module(arguments, command)
 255
 256            # Creates a mount point of the remote share on the local machine
 257            elif command == "mount":
 258                self.command_mount(arguments, command)
 259
 260            # Reconnects the current SMB session
 261            elif command in ["connect", "reconnect"]:
 262                self.command_reconnect(arguments, command)
 263
 264            # Reset the TTY output
 265            elif command == "reset":
 266                self.command_reset(arguments, command)
 267
 268            # Removes a remote file
 269            elif command == "rm":
 270                self.command_rm(arguments, command)
 271                
 272            # Removes a remote directory
 273            elif command == "rmdir":
 274                self.command_rmdir(arguments, command)
 275
 276            # Sessions management
 277            elif command == "sessions":
 278                self.sessionsManager.process_command_line(arguments)
 279
 280            # List shares
 281            elif command == "sizeof":
 282                self.command_sizeof(arguments, command)
 283
 284            # List shares
 285            elif command == "shares":
 286                self.command_shares(arguments, command)
 287            
 288            # Displays a tree view of the CWD
 289            elif command == "tree":
 290                self.command_tree(arguments, command)
 291            
 292            # Use a share
 293            elif command == "use":
 294                self.command_use(arguments, command)
 295        
 296        # Fallback to unknown command   
 297        else:
 298            self.logger.print("Unknown command. Type \"help\" for help.")
 299
 300    # Commands ================================================================
 301
 302    def command_debug(self, arguments, command):
 303        try:
 304            self.logger.print("[debug] command    = '%s'" % command)
 305            self.logger.print("[debug] arguments  = %s" % arguments)
 306        except Exception as e:
 307            traceback.print_exc()
 308
 309    @command_arguments_required
 310    @active_smb_connection_needed
 311    @smb_share_is_set
 312    def command_bat(self, arguments, command):
 313        # Command arguments required   : Yes
 314        # Active SMB connection needed : Yes
 315        # SMB share needed             : Yes
 316
 317        # Parse wildcards
 318        files_and_directories = resolve_local_files(arguments)
 319
 320        for path_to_file in files_and_directories:
 321            if self.sessionsManager.current_session.path_isfile(pathFromRoot=path_to_file):
 322                # Read the file
 323                try:    
 324                    rawcontents = self.sessionsManager.current_session.read_file(path=path_to_file)
 325                    if rawcontents is not None:
 326                        encoding = charset_normalizer.detect(rawcontents)["encoding"]
 327                        if encoding is not None:
 328                            filecontent = rawcontents.decode(encoding).rstrip()
 329                            lexer = Syntax.guess_lexer(path=ntpath.basename(path_to_file), code=filecontent)
 330                            # Some trickery for the files undetected by the lexer
 331                            if lexer == "default":
 332                                if '<?xml' in filecontent:
 333                                    lexer = "xml"
 334                                elif '<html>' in filecontent:
 335                                    lexer = "html"
 336                            syntax = Syntax(code=filecontent, line_numbers=True, lexer=lexer)
 337                            if len(files_and_directories) > 1:
 338                                self.logger.print("\x1b[1;93m[>] %s\x1b[0m" % (path_to_file+' ').ljust(80,'='))
 339                            Console().print(syntax)
 340                        else:
 341                            self.logger.error("[!] Could not detect charset of '%s'." % path_to_file)
 342                except impacket.smbconnection.SessionError as e:
 343                    self.logger.error("[!] SMB Error: %s" % e)
 344
 345    @command_arguments_required
 346    @active_smb_connection_needed
 347    @smb_share_is_set
 348    def command_cd(self, arguments, command):
 349        # Command arguments required   : Yes
 350        # Active SMB connection needed : Yes
 351        # SMB share needed             : Yes
 352
 353        try:
 354            self.sessionsManager.current_session.set_cwd(path=arguments[0])
 355        except impacket.smbconnection.SessionError as e:
 356            self.logger.error("[!] SMB Error: %s" % e)
 357
 358    @command_arguments_required
 359    @active_smb_connection_needed
 360    @smb_share_is_set
 361    def command_cat(self, arguments, command):
 362        # Command arguments required   : Yes
 363        # Active SMB connection needed : Yes
 364        # SMB share needed             : Yes
 365
 366        # Parse wildcards
 367        files_and_directories = resolve_local_files(arguments)
 368
 369        for path_to_file in files_and_directories:
 370            if self.sessionsManager.current_session.path_isfile(pathFromRoot=path_to_file):
 371                # Read the file
 372                try:
 373                    rawcontents = self.sessionsManager.current_session.read_file(path=path_to_file)
 374                    if rawcontents is not None:
 375                        encoding = charset_normalizer.detect(rawcontents)["encoding"]
 376                        if encoding is not None:
 377                            filecontent = rawcontents.decode(encoding).rstrip()
 378                            if len(files_and_directories) > 1:
 379                                self.logger.print("\x1b[1;93m[>] %s\x1b[0m" % (path_to_file+' ').ljust(80,'='))
 380                            self.logger.print(filecontent)
 381                        else:
 382                            self.logger.error("[!] Could not detect charset of '%s'." % path_to_file)
 383                except impacket.smbconnection.SessionError as e:
 384                    self.logger.error("[!] SMB Error: %s" % e)
 385
 386    def command_close(self, arguments, command):
 387        # Command arguments required   : No
 388        # Active SMB connection needed : No
 389        # SMB share needed             : No
 390
 391        self.sessionsManager.current_session.ping_smb_session()
 392        if self.sessionsManager.current_session.connected:
 393            self.sessionsManager.current_session.close_smb_session()
 394
 395    @command_arguments_required
 396    @active_smb_connection_needed
 397    @smb_share_is_set
 398    def command_get(self, arguments, command):
 399        # Command arguments required   : Yes
 400        # Active SMB connection needed : Yes
 401        # SMB share needed             : Yes
 402
 403        is_recursive = False
 404        while '-r' in arguments:
 405            is_recursive = True
 406            arguments.remove('-r')
 407
 408        # Parse wildcards
 409        files_and_directories = resolve_remote_files(self.sessionsManager.current_session, arguments)
 410
 411        # 
 412        for remotepath in files_and_directories:
 413            try:
 414                if is_recursive and self.sessionsManager.current_session.path_isdir(remotepath):
 415                    # Get files recursively
 416                    self.sessionsManager.current_session.get_file_recursively(path=remotepath)
 417                else:
 418                    # Get this single file
 419                    self.sessionsManager.current_session.get_file(path=remotepath)
 420            except impacket.smbconnection.SessionError as e:
 421                self.logger.error("[!] SMB Error: %s" % e)
 422
 423    def command_help(self, arguments, command):
 424        # Command arguments required   : No
 425        # Active SMB connection needed : No
 426        # SMB share needed             : No
 427
 428        if len(arguments) != 0:
 429            self.commandCompleterObject.print_help(command=arguments[0])
 430        else:
 431            self.commandCompleterObject.print_help(command=None)
 432
 433    @active_smb_connection_needed
 434    def command_info(self, arguments, command):
 435        # Command arguments required   : No
 436        # Active SMB connection needed : Yes
 437        # SMB share needed             : No
 438
 439        print_server_info = False
 440        print_share_info = False
 441        if len(arguments) != 0:
 442            print_server_info = (arguments[0].lower() == "server")
 443            print_share_info = (arguments[0].lower() == "share")
 444        else:
 445            print_server_info = True
 446            print_share_info = True
 447
 448        try:
 449            self.sessionsManager.current_session.info(
 450                share=print_share_info,
 451                server=print_server_info
 452            )
 453        except impacket.smbconnection.SessionError as e:
 454            self.logger.error("[!] SMB Error: %s" % e)
 455
 456    @command_arguments_required
 457    def command_lbat(self, arguments, command):
 458        # Command arguments required   : Yes
 459        # Active SMB connection needed : No
 460        # SMB share needed             : No
 461
 462        # Parse wildcards
 463        files_and_directories = resolve_remote_files(self.sessionsManager.current_session, arguments)
 464
 465        for path_to_file in files_and_directories:
 466            # Read the file
 467            try:
 468                if os.path.exists(path=path_to_file):
 469                    f = open(path_to_file, 'rb')
 470                    rawcontents = f.read()
 471                    #
 472                    if rawcontents is not None:
 473                        encoding = charset_normalizer.detect(rawcontents)["encoding"]
 474                        if encoding is not None:
 475                            filecontent = rawcontents.decode(encoding).rstrip()
 476                            lexer = Syntax.guess_lexer(path=ntpath.basename(path_to_file), code=filecontent)
 477                            # Some trickery for the files undetected by the lexer
 478                            if lexer == "default":
 479                                if '<?xml' in filecontent:
 480                                    lexer = "xml"
 481                                elif '<html>' in filecontent:
 482                                    lexer = "html"
 483                            syntax = Syntax(code=filecontent, line_numbers=True, lexer=lexer)
 484                            if len(files_and_directories) > 1:
 485                                self.logger.print("\x1b[1;93m[>] %s\x1b[0m" % (path_to_file+' ').ljust(80,'='))
 486                            Console().print(syntax)
 487                        else:
 488                            self.logger.error("[!] Could not detect charset of '%s'." % path_to_file)
 489                else:
 490                    self.logger.error("[!] Local file '%s' does not exist." % path_to_file)
 491            except impacket.smbconnection.SessionError as e:
 492                self.logger.error("[!] SMB Error: %s" % e)
 493
 494    @command_arguments_required
 495    def command_lcat(self, arguments, command):
 496        # Command arguments required   : Yes
 497        # Active SMB connection needed : No
 498        # SMB share needed             : No
 499
 500        # Parse wildcards
 501        files_and_directories = resolve_remote_files(self.sessionsManager.current_session, arguments)
 502
 503        for path_to_file in files_and_directories:
 504            # Read the file 
 505            try:
 506                if os.path.exists(path=path_to_file):
 507                    f = open(path_to_file, 'rb')
 508                    rawcontents = f.read()
 509                    #
 510                    if rawcontents is not None:
 511                        encoding = charset_normalizer.detect(rawcontents)["encoding"]
 512                        if encoding is not None:
 513                            filecontent = rawcontents.decode(encoding).rstrip()
 514                            if len(files_and_directories) > 1:
 515                                self.logger.print("\x1b[1;93m[>] %s\x1b[0m" % (path_to_file+' ').ljust(80,'='))
 516                            self.logger.print(filecontent)
 517                        else:
 518                            self.logger.error("[!] Could not detect charset of '%s'." % path_to_file)
 519                else:
 520                    self.logger.error("[!] Local file '%s' does not exist." % path_to_file)
 521            except impacket.smbconnection.SessionError as e:
 522                self.logger.error("[!] SMB Error: %s" % e)
 523
 524    @command_arguments_required
 525    def command_lcd(self, arguments, command):
 526        # Command arguments required   : Yes
 527        # Active SMB connection needed : No
 528        # SMB share needed             : No
 529        
 530        path = arguments[0]
 531
 532        if os.path.exists(path=path):
 533            if os.path.isdir(s=path):
 534                os.chdir(path=path)
 535            else:
 536                self.logger.error("Path '%s' is not a directory." % path)
 537        else:
 538            self.logger.error("Directory '%s' does not exists." % path)
 539
 540    @command_arguments_required
 541    def command_lcp(self, arguments, command):
 542        # Command arguments required   : Yes
 543        # Active SMB connection needed : No
 544        # SMB share needed             : No
 545
 546        if len(arguments) == 2:
 547            src_path = arguments[0]
 548            dst_path = arguments[1]
 549            if os.path.exists(path=src_path):
 550                try:
 551                    shutil.copyfile(src=src_path, dst=dst_path)
 552                except shutil.SameFileError as err:
 553                    self.logger.error("[!] Error: %s" % err)
 554            else:
 555                self.logger.error("[!] File '%s' does not exists." % src_path)
 556        else:
 557            self.commandCompleterObject.print_help(command=command)
 558
 559    def command_lls(self, arguments, command):
 560        # Command arguments required   : No
 561        # Active SMB connection needed : No
 562        # SMB share needed             : No
 563
 564        if len(arguments) == 0:
 565            arguments = ['.']
 566        else:
 567            arguments = resolve_local_files(arguments)
 568
 569        for path in arguments:
 570            if len(arguments) > 1:
 571                self.logger.print("%s:" % path)
 572            # lls <directory>
 573            if os.path.isdir(path):
 574                directory_contents = os.listdir(path=path)
 575                for entryname in sorted(directory_contents):
 576                    path_to_file = path + os.path.sep + entryname
 577                    rights_str = unix_permissions(path_to_file)
 578                    size_str = b_filesize(os.path.getsize(filename=path_to_file))
 579                    date_str = datetime.datetime.fromtimestamp(os.path.getmtime(filename=path_to_file)).strftime("%Y-%m-%d %H:%M")
 580
 581                    if os.path.isdir(s=entryname):
 582                        if self.config.no_colors:
 583                            self.logger.print("%s %10s  %s  %s%s" % (rights_str, size_str, date_str, entryname, os.path.sep))
 584                        else:
 585                            self.logger.print("%s %10s  %s  \x1b[1;96m%s\x1b[0m%s" % (rights_str, size_str, date_str, entryname, os.path.sep))
 586                    else:
 587                        if self.config.no_colors:
 588                            self.logger.print("%s %10s  %s  %s" % (rights_str, size_str, date_str, entryname))
 589                        else:
 590                            self.logger.print("%s %10s  %s  \x1b[1m%s\x1b[0m" % (rights_str, size_str, date_str, entryname))
 591            # lls <file>
 592            elif os.path.isfile(path):
 593                rights_str = unix_permissions(path)
 594                size_str = b_filesize(os.path.getsize(filename=path))
 595                date_str = datetime.datetime.fromtimestamp(os.path.getmtime(filename=path)).strftime("%Y-%m-%d %H:%M")
 596                if self.config.no_colors:
 597                    self.logger.print("%s %10s  %s  %s" % (rights_str, size_str, date_str, os.path.basename(path)))
 598                else:
 599                    self.logger.print("%s %10s  %s  \x1b[1m%s\x1b[0m" % (rights_str, size_str, date_str, os.path.basename(path))) 
 600            
 601            if len(arguments) > 1:
 602                self.logger.print()
 603
 604    @command_arguments_required
 605    def command_lmkdir(self, arguments, command):
 606        # Command arguments required   : Yes
 607        # Active SMB connection needed : No
 608        # SMB share needed             : No
 609
 610        for path in arguments:
 611            if os.path.sep in path:
 612                path = path.strip(os.path.sep).split(os.path.sep)
 613            else:
 614                path = [path]
 615
 616            # Create each dir in the path
 617            for depth in range(1, len(path)+1):
 618                tmp_path = os.path.sep.join(path[:depth])
 619                if not os.path.exists(tmp_path):
 620                    os.mkdir(path=tmp_path)
 621
 622    def command_lpwd(self, arguments, command):
 623        # Command arguments required   : No
 624        # Active SMB connection needed : No
 625        # SMB share needed             : No
 626
 627        self.logger.print(os.getcwd())
 628
 629    @command_arguments_required
 630    def command_lrename(self, arguments, command):
 631        # Command arguments required   : Yes
 632        # Active SMB connection needed : No
 633        # SMB share needed             : No
 634
 635        if len(arguments) == 2:
 636            os.rename(src=arguments[0], dst=arguments[1])
 637        else:
 638            self.commandCompleterObject.print_help(command=command)
 639
 640    @command_arguments_required
 641    def command_lrm(self, arguments, command):
 642        # Command arguments required   : Yes
 643        # Active SMB connection needed : No
 644        # SMB share needed             : No
 645
 646        path = arguments[0]
 647
 648        if os.path.exists(path):
 649            if not os.path.isdir(s=path):
 650                try:
 651                    os.remove(path=path)
 652                except Exception as e:
 653                    self.logger.error("Error removing file '%s' : %s" % path)
 654            else:
 655                self.logger.error("Cannot delete '%s'. It is a directory, use 'lrmdir <directory>' instead." % path)
 656        else:
 657            self.logger.error("Path '%s' does not exist." % path)
 658
 659    @command_arguments_required
 660    def command_lrmdir(self, arguments, command):
 661        # Command arguments required   : Yes
 662        # Active SMB connection needed : No
 663        # SMB share needed             : No
 664
 665        if len(arguments) == 0:
 666            path = '.'
 667        else:
 668            path = arguments[0]
 669
 670        if os.path.exists(path):
 671            if os.path.isdir(s=path):
 672                try:
 673                    shutil.rmtree(path=path)
 674                except Exception as e:
 675                    self.logger.error("Error removing directory '%s' : %s" % path)
 676            else:
 677                self.logger.error("Cannot delete '%s'. It is a file, use 'lrm <file>' instead." % path)
 678        else:
 679            self.logger.error("Path '%s' does not exist." % path)
 680
 681    def command_ltree(self, arguments, command):
 682        # Command arguments required   : No
 683        # Active SMB connection needed : No
 684        # SMB share needed             : No
 685
 686        if len(arguments) == 0:
 687            path = '.'
 688        else:
 689            path = arguments[0]
 690
 691        if len(arguments) == 0:
 692            local_tree(path='.', config=self.config)
 693        else:
 694            local_tree(path=path, config=self.config)
 695
 696    @active_smb_connection_needed
 697    @smb_share_is_set
 698    def command_ls(self, arguments, command):
 699        # Command arguments required   : No
 700        # Active SMB connection needed : Yes
 701        # SMB share needed             : Yes
 702
 703        if len(arguments) == 0:
 704            arguments = ['.']
 705        else:
 706            arguments = resolve_remote_files(self.sessionsManager.current_session, arguments)
 707
 708        for path in arguments:
 709            if len(arguments) > 1:
 710                self.logger.print("%s:" % path)
 711
 712            if self.sessionsManager.current_session.path_isdir(pathFromRoot=path):
 713                # Read the files
 714                directory_contents = self.sessionsManager.current_session.list_contents(path=path)
 715            else:
 716                entry = self.sessionsManager.current_session.get_entry(path=path)
 717                if entry is not None:
 718                    directory_contents = {entry.get_longname(): entry}
 719                else:
 720                    directory_contents = {}
 721
 722            for longname in sorted(directory_contents.keys(), key=lambda x:x.lower()):
 723                windows_ls_entry(directory_contents[longname], self.config)
 724
 725            if len(arguments) > 1:
 726                self.logger.print()
 727            
 728    @command_arguments_required
 729    @active_smb_connection_needed
 730    @smb_share_is_set
 731    def command_mkdir(self, arguments, command):
 732        # Command arguments required   : Yes
 733        # Active SMB connection needed : Yes
 734        # SMB share needed             : Yes
 735
 736        self.sessionsManager.current_session.mkdir(path=arguments[0])
 737
 738    @command_arguments_required
 739    @active_smb_connection_needed
 740    @smb_share_is_set
 741    def command_module(self, arguments, command):
 742        module_name = arguments[0]
 743
 744        if module_name in self.modules.keys():
 745            module = self.modules[module_name](self.sessionsManager.current_session, self.config, self.logger)
 746            arguments_string = ' '.join(arguments[1:])
 747            module.run(arguments_string)
 748        else:
 749            self.logger.error("Module '%s' does not exist." % module_name)
 750
 751    @command_arguments_required
 752    @active_smb_connection_needed
 753    @smb_share_is_set
 754    def command_mount(self, arguments, command):
 755        # Command arguments required   : Yes
 756        # Active SMB connection needed : Yes
 757        # SMB share needed             : Yes
 758
 759        if len(arguments) == 2:
 760            remote_path = arguments[0]
 761            if not remote_path.startswith(ntpath.sep):
 762                remote_path = self.sessionsManager.current_session.smb_cwd + ntpath.sep + remote_path
 763
 764            local_mount_point = arguments[1]
 765
 766            self.logger.debug("Trying to mount remote '%s' onto local '%s'" % (remote_path, local_mount_point))
 767
 768            try:
 769                self.sessionsManager.current_session.mount(local_mount_point, remote_path)
 770            except (impacket.smbconnection.SessionError, impacket.smb3.SessionError) as e:
 771                self.sessionsManager.current_session.umount(local_mount_point)
 772        else:
 773            self.commandCompleterObject.print_help(command=command)
 774
 775    @command_arguments_required
 776    @active_smb_connection_needed
 777    @smb_share_is_set
 778    def command_put(self, arguments, command):
 779        # Command arguments required   : Yes
 780        # Active SMB connection needed : Yes
 781        # SMB share needed             : Yes
 782        
 783        is_recursive = False
 784        while '-r' in arguments:
 785            is_recursive = True
 786            arguments.remove('-r')
 787
 788        # Parse wildcards
 789        files_and_directories = resolve_local_files(arguments)
 790
 791        # 
 792        for localpath in files_and_directories:
 793            try:
 794                self.logger.print(localpath)
 795                if is_recursive and os.path.isdir(s=localpath):
 796                    # Put files recursively
 797                    self.sessionsManager.current_session.put_file_recursively(localpath=localpath)
 798                else:
 799                    # Put this single file
 800                    self.sessionsManager.current_session.put_file(localpath=localpath)
 801            except impacket.smbconnection.SessionError as e:
 802                self.logger.error("[!] SMB Error: %s" % e)
 803
 804    def command_reconnect(self, arguments, command):
 805        # Command arguments required   : No
 806        # Active SMB connection needed : No
 807        # SMB share needed             : No
 808
 809        self.sessionsManager.current_session.ping_smb_session()
 810        if self.sessionsManager.current_session.connected:
 811            self.sessionsManager.current_session.close_smb_session()
 812            self.sessionsManager.current_session.init_smb_session()
 813        else:
 814            self.sessionsManager.current_session.init_smb_session()
 815
 816    def command_reset(self, arguments, command):
 817        # Command arguments required   : No
 818        # Active SMB connection needed : No
 819        # SMB share needed             : No
 820        sys.stdout.write('\x1b[?25h') # Sets the cursor to on
 821        sys.stdout.write('\x1b[v')  
 822        sys.stdout.write('\x1b[o') # Reset
 823        sys.stdout.flush()
 824
 825    @command_arguments_required
 826    @active_smb_connection_needed
 827    @smb_share_is_set
 828    def command_rm(self, arguments, command):
 829        # Command arguments required   : Yes
 830        # Active SMB connection needed : Yes
 831        # SMB share needed             : Yes
 832
 833        for path_to_file in arguments:
 834            # Wildcard
 835            if '*' in path_to_file:
 836                self.sessionsManager.current_session.rm(path=path_to_file)
 837            # File
 838            elif self.sessionsManager.current_session.path_exists(path_to_file):
 839                if self.sessionsManager.current_session.path_isfile(path_to_file):
 840                    try:
 841                        self.sessionsManager.current_session.rm(path=path_to_file)
 842                    except Exception as e:
 843                        self.logger.error("Error removing file '%s' : %s" % path_to_file)
 844                else:
 845                    self.logger.error("Cannot delete '%s': This is a directory, use 'rmdir <directory>' instead." % path_to_file)
 846            # File does not exist
 847            else:
 848                self.logger.error("Remote file '%s' does not exist." % path_to_file)
 849
 850    @command_arguments_required
 851    @active_smb_connection_needed
 852    @smb_share_is_set
 853    def command_rmdir(self, arguments, command):
 854        # Command arguments required   : Yes
 855        # Active SMB connection needed : Yes
 856        # SMB share needed             : Yes
 857
 858        for path_to_directory in arguments:
 859            if self.sessionsManager.current_session.path_exists(path_to_directory):
 860                if self.sessionsManager.current_session.path_isdir(path_to_directory):
 861                    try:
 862                        self.sessionsManager.current_session.rmdir(path=path_to_directory)
 863                    except Exception as e:
 864                        self.logger.error("Error removing directory '%s' : %s" % path_to_directory)
 865                else:
 866                    self.logger.error("Cannot delete '%s': This is a file, use 'rm <file>' instead." % path_to_directory)
 867            else:
 868                self.logger.error("Remote directory '%s' does not exist." % path_to_directory)
 869
 870    @active_smb_connection_needed
 871    @smb_share_is_set
 872    def command_sizeof(self, arguments, command):
 873        # Command arguments required   : Yes
 874        # Active SMB connection needed : Yes
 875        # SMB share needed             : Yes
 876
 877        class RecursiveSizeOfPrint(object):
 878            def __init__(self, entry, sessionsManager, config, logger):
 879                self.entry = entry
 880                self.config = config
 881                self.logger = logger
 882                self.sessionsManager = sessionsManager
 883                self.size = 0
 884            
 885            def update(self, entry, fullpath, depth):
 886                self.size += entry.get_filesize()
 887                self.print(end='\r')
 888            
 889            def print(self, end='\n'):
 890                # Directory
 891                if self.entry.is_directory():
 892                    if self.config.no_colors:
 893                        path = "%s\\" % self.entry.get_longname()
 894                    else:
 895                        path = "\x1b[1;96m%s\x1b[0m\\" % self.entry.get_longname()
 896                # File
 897                else:
 898                    if self.config.no_colors:
 899                        path = "%s" % self.entry.get_longname()
 900                    else:
 901                        path = "\x1b[1m%s\x1b[0m" % self.entry.get_longname()
 902                self.logger.print("%10s  %s" % (b_filesize(self.size), path), end=end)
 903
 904        entries = []
 905        if len(arguments) == 0:
 906            entries = self.sessionsManager.current_session.list_contents()
 907            entries = [entry for name, entry in entries.items() if name not in ['.', '..']]
 908        else:
 909            entry = self.sessionsManager.current_session.get_entry(path=' '.join(arguments))
 910            entries = []
 911            if entry is not None:
 912                entries = [entry]
 913            else:
 914                self.logger.print("[!] Path '%s' does not exist." % ' '.join(arguments))
 915
 916        total = 0
 917        for entry in entries:
 918            rsop = RecursiveSizeOfPrint(
 919                entry=entry, 
 920                sessionsManager=self.sessionsManager, 
 921                config=self.config,
 922                logger=self.logger
 923            )
 924            # Directory
 925            if entry.is_directory():
 926                self.sessionsManager.current_session.find(
 927                    paths=[entry.get_longname()],
 928                    callback=rsop.update
 929                )
 930            # File
 931            else:
 932                rsop.update(entry=entry, fullpath=entry.get_longname(), depth=0)
 933            # Close the print
 934            rsop.print()
 935            total += rsop.size
 936        
 937        if len(entries) > 1:
 938            self.logger.print("──────────────────────")
 939            self.logger.print("     total  %s" % b_filesize(total))
 940
 941    @active_smb_connection_needed
 942    def command_shares(self, arguments, command):
 943        # Command arguments required   : No
 944        # Active SMB connection needed : Yes
 945        # SMB share needed             : No
 946
 947        do_check_rights = False
 948        if len(arguments) != 0:
 949            if arguments[0] == "rights":
 950                do_check_rights = True
 951
 952        shares = self.sessionsManager.current_session.list_shares()
 953        if len(shares.keys()) != 0:
 954            table = Table(title=None)
 955            table.add_column("Share")
 956            table.add_column("Visibility")
 957            table.add_column("Type")
 958            table.add_column("Description", justify="left")
 959            if do_check_rights:
 960                table.add_column("Rights")
 961
 962            for sharename in sorted(shares.keys()):
 963                types = ', '.join([s.replace("STYPE_","") for s in shares[sharename]["type"]])
 964
 965                is_hidden = bool(sharename.endswith('$'))
 966                if is_hidden:
 967                    str_hidden = "[bold bright_blue]Hidden[/bold bright_blue]"
 968                    str_sharename = "[bold bright_blue]" + shares[sharename]["name"] + "[/bold bright_blue]"
 969                    str_types = "[bold bright_blue]" + types + "[/bold bright_blue]"
 970                    str_comment = "[bold bright_blue]" + shares[sharename]["comment"] + "[/bold bright_blue]"
 971                else:
 972                    str_hidden = "[bold bright_yellow]Visible[/bold bright_yellow]"
 973                    str_sharename = "[bold bright_yellow]" + shares[sharename]["name"] + "[/bold bright_yellow]"
 974                    str_types = "[bold bright_yellow]" + types + "[/bold bright_yellow]"
 975                    str_comment = "[bold bright_yellow]" + shares[sharename]["comment"] + "[/bold bright_yellow]"
 976
 977                if do_check_rights:
 978                    access_rights = self.sessionsManager.current_session.test_rights(sharename=shares[sharename]["name"])
 979                    str_access_rights = "[bold yellow]NO ACCESS[/bold yellow]"
 980                    if access_rights["readable"] and access_rights["writable"]:
 981                        str_access_rights = "[bold green]READ[/bold green], [bold red]WRITE[/bold red]"
 982                    elif access_rights["readable"]:
 983                        str_access_rights = "[bold green]READ[/bold green]"
 984                    elif access_rights["writable"]:
 985                        # Without READ?? This should not happen IMHO
 986                        str_access_rights = "[bold red]WRITE[/bold red]"
 987                    else:
 988                        str_access_rights = "[bold yellow]NO ACCESS[/bold yellow]"
 989
 990                if do_check_rights:
 991                    table.add_row(str_sharename, str_hidden, str_types, str_comment, str_access_rights)
 992                else:
 993                    table.add_row(str_sharename, str_hidden, str_types, str_comment)
 994
 995            Console().print(table)
 996        else:
 997            self.logger.error("No share served on '%s'" % self.sessionsManager.current_session.host)
 998
 999    @active_smb_connection_needed
1000    @smb_share_is_set
1001    def command_tree(self, arguments, command):
1002        # Command arguments required   : No
1003        # Active SMB connection needed : Yes
1004        # SMB share needed             : Yes
1005
1006        if len(arguments) == 0:
1007            self.sessionsManager.current_session.tree(path='.')
1008        else:
1009            self.sessionsManager.current_session.tree(path=arguments[0])
1010
1011    @command_arguments_required
1012    @active_smb_connection_needed
1013    @smb_share_is_set
1014    def command_umount(self, arguments, command):
1015        # Command arguments required   : Yes
1016        # Active SMB connection needed : Yes
1017        # SMB share needed             : Yes
1018
1019        local_mount_point = arguments[0]
1020
1021        self.logger.debug("Trying to unmount local mount point '%s'" % (local_mount_point))
1022        
1023        self.sessionsManager.current_session.umount(local_mount_point)
1024        
1025    @command_arguments_required
1026    @active_smb_connection_needed
1027    def command_use(self, arguments, command):
1028        # Command arguments required   : Yes
1029        # Active SMB connection needed : Yes
1030        # SMB share needed             : No
1031
1032        sharename = arguments[0]
1033
1034        # Reload the list of shares
1035        shares = self.sessionsManager.current_session.list_shares()
1036        shares = [s.lower() for s in shares.keys()]
1037
1038        if sharename.lower() in shares:
1039            self.sessionsManager.current_session.set_share(sharename)
1040        else:
1041            self.logger.error("No share named '%s' on '%s'" % (sharename, self.sessionsManager.current_session.host))
1042
1043    # Private functions =======================================================
1044
1045    def __load_modules(self):
1046        """
1047        Dynamically loads all Python modules from the 'modules' directory and stores them in the 'modules' dictionary.
1048        Each module is expected to be a Python file that contains a class with the same name as the file (minus the .py extension).
1049        The class must have at least two attributes: 'name' and 'description'.
1050        
1051        This method clears any previously loaded modules, constructs the path to the modules directory, and iterates over
1052        each file in that directory. If the file is a Python file (ends with .py and is not '__init__.py'), it attempts to
1053        import the module and access the class within it to add to the 'modules' dictionary.
1054        
1055        If debug mode is enabled in the configuration, it prints debug information about the loading process and the loaded modules.
1056        """
1057
1058        self.modules.clear()
1059
1060        modules_dir = os.path.normpath(os.path.dirname(__file__) + os.path.sep + ".." + os.path.sep + "modules")
1061        self.logger.debug("Loading modules from %s ..." % modules_dir)
1062        sys.path.extend([modules_dir])
1063
1064        for file in os.listdir(modules_dir):
1065            filepath = os.path.normpath(modules_dir + os.path.sep + file)
1066            if file.endswith('.py'):
1067                if os.path.isfile(filepath) and file not in ["__init__.py"]:
1068                    try:
1069                        module_file = import_module('smbclientng.modules.%s' % (file[:-3]))
1070                        module = module_file.__getattribute__(file[:-3])
1071                        self.modules[module.name.lower()] = module
1072                    except AttributeError as e:
1073                        pass
1074
1075        if self.config.debug:
1076            if len(self.modules.keys()) == 0:
1077                self.logger.debug("Loaded 0 modules.")
1078            elif len(self.modules.keys()) == 1:
1079                self.logger.debug("Loaded 1 module:")
1080            else:
1081                self.logger.debug("Loaded %d modules:" % len(self.modules.keys()))
1082            for modulename in sorted(self.modules.keys()):
1083                self.logger.debug("%s : \"%s\" (%s)" % (self.modules[modulename].name, self.modules[modulename].description, self.modules[modulename]))
1084
1085        if self.commandCompleterObject is not None:
1086            self.commandCompleterObject.commands["module"]["subcommands"] = list(self.modules.keys())
1087
1088    def __prompt(self):
1089        """
1090        Prints the command prompt for the interactive shell.
1091
1092        This method constructs and returns the command prompt string based on the current state of the SMB session.
1093        The prompt indicates the connection status with a visual symbol and displays the current working directory
1094        or the SMB share path. The prompt appearance changes based on whether colors are enabled in the configuration.
1095
1096        Returns:
1097            str: The formatted command prompt string.
1098        """
1099
1100        # A session exists
1101        if self.sessionsManager.current_session is not None:
1102            # Check if the session is still active
1103            self.sessionsManager.current_session.ping_smb_session()
1104            if self.sessionsManager.current_session.connected:
1105                if self.config.no_colors:
1106                    connected_dot = "[v]"
1107                else:
1108                    connected_dot = "\x1b[1;92m⏺\x1b[0m"
1109            else:
1110                if self.config.no_colors:
1111                    connected_dot = "[x]"
1112                else:
1113                    connected_dot = "\x1b[1;91m⏺\x1b[0m"
1114            
1115            # Session ID if 
1116            session_prompt = ""
1117            if len(self.sessionsManager.sessions.keys()) >= 2:
1118                session_prompt = "[#%d]" % self.sessionsManager.current_session_id
1119
1120            # No share set yet
1121            if self.sessionsManager.current_session.smb_share is None:
1122                str_path = "\\\\%s\\" % self.sessionsManager.current_session.host
1123            # A share is set
1124            else:
1125                if len(self.sessionsManager.current_session.smb_cwd) == 0:
1126                    current_path = ""
1127                else:
1128                    current_path = self.sessionsManager.current_session.smb_cwd.strip(ntpath.sep) + ntpath.sep
1129                
1130                str_path = "\\\\%s\\%s\\%s" % (self.sessionsManager.current_session.host, self.sessionsManager.current_session.smb_share, current_path)
1131        # No active session
1132        else:
1133            connected_dot = ""
1134            session_prompt = ""
1135            str_path = "No active session"
1136
1137        # Build final prompt string
1138        if self.config.no_colors:
1139            str_prompt = "%s%s[%s]> " % (connected_dot, session_prompt, str_path)
1140        else:
1141            str_prompt = "%s%s[\x1b[1;94m%s\x1b[0m]> " % (connected_dot, session_prompt, str_path)
1142
1143        return str_prompt

Class InteractiveShell is designed to manage the interactive command line interface for smbclient-ng.

This class handles user input, executes commands, and manages the state of the SMB session. It provides a command line interface for users to interact with SMB shares, execute commands like directory listing, file transfer, and more.

Attributes: smbSession (SMBConnection): The active SMB connection session. debug (bool): Flag to enable or disable debug mode. smb_share (str): The current SMB share in use. smb_path (str): The current path within the SMB share. commandCompleterObject (CommandCompleter): Object to handle command completion and help generation.

Methods: __init__(self, smbSession, debug=False): Initializes the InteractiveShell with the given SMB session and debug mode. run(self): Starts the command line interface loop, processing user input until exit.

InteractiveShell(sessionsManager, config, logger)
 85    def __init__(self, sessionsManager, config, logger):
 86        # Objects
 87        self.sessionsManager = sessionsManager
 88        self.config = config
 89        self.logger = logger
 90        # Internals
 91        self.commandCompleterObject = CommandCompleter(
 92            smbSession=self.sessionsManager.current_session,
 93            config=self.config,
 94            logger=self.logger,
 95        )
 96        readline.set_completer(self.commandCompleterObject.complete)
 97        readline.parse_and_bind("tab: complete")
 98        readline.set_completer_delims("\n")
 99        # Additional modules
100        self.__load_modules()
running = True
modules = {}
sessionsManager
config
logger
commandCompleterObject
def run(self):
102    def run(self):
103        # Read commands from script file first
104        if self.config.startup_script:
105            f = open(self.config.startup_script, 'r')
106            for line in f.readlines():
107                try:
108                    self.logger.print("%s%s" % (self.__prompt(), line.strip()))
109                    readline.add_history(line.strip())
110                    self.process_line(commandLine=line.strip())
111                except KeyboardInterrupt as e:
112                    self.logger.print()
113
114                except EOFError as e:
115                    self.logger.print()
116                    running = False
117
118                except Exception as err:
119                    if self.config.debug:
120                        traceback.print_exc()
121                    self.logger.error(str(err))
122
123        # Then interactive console
124        if not self.config.not_interactive:
125            while self.running:
126                try:
127                    user_input = input(self.__prompt()).strip()
128                    self.process_line(commandLine=user_input)
129                except KeyboardInterrupt as e:
130                    self.logger.print()
131
132                except EOFError as e:
133                    self.logger.print()
134                    running = False
135
136                except Exception as err:
137                    if self.config.debug:
138                        traceback.print_exc()
139                    self.logger.error(str(err))
def process_line(self, commandLine):
141    def process_line(self, commandLine):
142        # Split and parse the commandLine
143        tokens = shlex.split(commandLine)
144        if len(tokens) == 0:
145            command = ""
146            arguments = []
147        elif len(tokens) == 1:
148            command = tokens[0].lower()
149            arguments = []
150        else:
151            command = tokens[0].lower()
152            arguments = tokens[1:]
153        
154        # Skip
155        if command.strip() == "":
156            pass
157        # Execute the command
158        elif command in self.commandCompleterObject.commands.keys():
159
160            # Exit the command line
161            if command in ["exit", "quit"]:
162                self.running = False
163            
164            # Display help
165            elif command == "help":
166                self.command_help(arguments, command)
167
168            # Cat the contents of a file
169            elif command == "bat":
170                self.command_bat(arguments, command)
171
172            # Cat the contents of a file
173            elif command == "cat":
174                self.command_cat(arguments, command)
175
176            # Closes the current SMB session
177            elif command == "close":
178                self.command_close(arguments, command)
179                
180            # Change directory in the current share
181            elif command == "cd":
182                self.command_cd(arguments, command)
183            
184            # debug
185            elif command == "debug":
186                self.command_debug(arguments, command)
187
188            # Get a file
189            elif command == "get":
190                self.command_get(arguments, command)
191
192            # SMB server info
193            elif command == "info":
194                self.command_info(arguments, command)
195
196            # List directory contents in a share
197            elif command in ["ls", "dir"]:
198                self.command_ls(arguments, command)
199
200            # Creates a new remote directory
201            elif command == "mkdir":
202                self.command_mkdir(arguments, command)
203
204            # Put a file
205            elif command == "put":
206                self.command_put(arguments, command)
207
208            # Shows the content of a local file
209            elif command == "lcat":
210                self.command_lcat(arguments, command)
211
212            # Changes the current local directory
213            elif command == "lcd":
214                self.command_lcd(arguments, command)
215
216            # Creates a copy of a local file
217            elif command == "lcp":
218                self.command_lcp(arguments, command)
219
220            # Pretty prints the content of a local file
221            elif command == "lbat":
222                self.command_lbat(arguments, command)
223
224            # Lists the contents of the current local directory
225            elif command == "lls":
226                self.command_lls(arguments, command)
227
228            # Creates a new local directory
229            elif command == "lmkdir":
230                self.command_lmkdir(arguments, command)
231
232            # Shows the current local directory
233            elif command == "lpwd":
234                self.command_lpwd(arguments, command)
235
236            # Renames a local file
237            elif command == "lrename":
238                self.command_lrename(arguments, command)
239            
240            # Removes a local file
241            elif command == "lrm":
242                self.command_lrm(arguments, command)
243
244            # Removes a local directory
245            elif command == "lrmdir":
246                self.command_lrmdir(arguments, command)
247
248            # Shows the current local directory
249            elif command == "ltree":
250                self.command_ltree(arguments, command)
251
252            # Modules
253            elif command == "module":
254                self.command_module(arguments, command)
255
256            # Creates a mount point of the remote share on the local machine
257            elif command == "mount":
258                self.command_mount(arguments, command)
259
260            # Reconnects the current SMB session
261            elif command in ["connect", "reconnect"]:
262                self.command_reconnect(arguments, command)
263
264            # Reset the TTY output
265            elif command == "reset":
266                self.command_reset(arguments, command)
267
268            # Removes a remote file
269            elif command == "rm":
270                self.command_rm(arguments, command)
271                
272            # Removes a remote directory
273            elif command == "rmdir":
274                self.command_rmdir(arguments, command)
275
276            # Sessions management
277            elif command == "sessions":
278                self.sessionsManager.process_command_line(arguments)
279
280            # List shares
281            elif command == "sizeof":
282                self.command_sizeof(arguments, command)
283
284            # List shares
285            elif command == "shares":
286                self.command_shares(arguments, command)
287            
288            # Displays a tree view of the CWD
289            elif command == "tree":
290                self.command_tree(arguments, command)
291            
292            # Use a share
293            elif command == "use":
294                self.command_use(arguments, command)
295        
296        # Fallback to unknown command   
297        else:
298            self.logger.print("Unknown command. Type \"help\" for help.")
def command_debug(self, arguments, command):
302    def command_debug(self, arguments, command):
303        try:
304            self.logger.print("[debug] command    = '%s'" % command)
305            self.logger.print("[debug] arguments  = %s" % arguments)
306        except Exception as e:
307            traceback.print_exc()
def command_bat(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_cd(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_cat(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_close(self, arguments, command):
386    def command_close(self, arguments, command):
387        # Command arguments required   : No
388        # Active SMB connection needed : No
389        # SMB share needed             : No
390
391        self.sessionsManager.current_session.ping_smb_session()
392        if self.sessionsManager.current_session.connected:
393            self.sessionsManager.current_session.close_smb_session()
def command_get(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_help(self, arguments, command):
423    def command_help(self, arguments, command):
424        # Command arguments required   : No
425        # Active SMB connection needed : No
426        # SMB share needed             : No
427
428        if len(arguments) != 0:
429            self.commandCompleterObject.print_help(command=arguments[0])
430        else:
431            self.commandCompleterObject.print_help(command=None)
def command_info(*args, **kwargs):
40    def wrapper(*args, **kwargs):
41        self, arguments,command  = args[0], args[1], args[2]
42        #
43        self.sessionsManager.current_session.ping_smb_session()
44        if self.sessionsManager.current_session.connected:
45            return func(*args, **kwargs)
46        else:
47            print("[!] SMB Session is disconnected.")
48            return None
def command_lbat(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_lcat(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_lcd(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_lcp(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_lls(self, arguments, command):
559    def command_lls(self, arguments, command):
560        # Command arguments required   : No
561        # Active SMB connection needed : No
562        # SMB share needed             : No
563
564        if len(arguments) == 0:
565            arguments = ['.']
566        else:
567            arguments = resolve_local_files(arguments)
568
569        for path in arguments:
570            if len(arguments) > 1:
571                self.logger.print("%s:" % path)
572            # lls <directory>
573            if os.path.isdir(path):
574                directory_contents = os.listdir(path=path)
575                for entryname in sorted(directory_contents):
576                    path_to_file = path + os.path.sep + entryname
577                    rights_str = unix_permissions(path_to_file)
578                    size_str = b_filesize(os.path.getsize(filename=path_to_file))
579                    date_str = datetime.datetime.fromtimestamp(os.path.getmtime(filename=path_to_file)).strftime("%Y-%m-%d %H:%M")
580
581                    if os.path.isdir(s=entryname):
582                        if self.config.no_colors:
583                            self.logger.print("%s %10s  %s  %s%s" % (rights_str, size_str, date_str, entryname, os.path.sep))
584                        else:
585                            self.logger.print("%s %10s  %s  \x1b[1;96m%s\x1b[0m%s" % (rights_str, size_str, date_str, entryname, os.path.sep))
586                    else:
587                        if self.config.no_colors:
588                            self.logger.print("%s %10s  %s  %s" % (rights_str, size_str, date_str, entryname))
589                        else:
590                            self.logger.print("%s %10s  %s  \x1b[1m%s\x1b[0m" % (rights_str, size_str, date_str, entryname))
591            # lls <file>
592            elif os.path.isfile(path):
593                rights_str = unix_permissions(path)
594                size_str = b_filesize(os.path.getsize(filename=path))
595                date_str = datetime.datetime.fromtimestamp(os.path.getmtime(filename=path)).strftime("%Y-%m-%d %H:%M")
596                if self.config.no_colors:
597                    self.logger.print("%s %10s  %s  %s" % (rights_str, size_str, date_str, os.path.basename(path)))
598                else:
599                    self.logger.print("%s %10s  %s  \x1b[1m%s\x1b[0m" % (rights_str, size_str, date_str, os.path.basename(path))) 
600            
601            if len(arguments) > 1:
602                self.logger.print()
def command_lmkdir(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_lpwd(self, arguments, command):
622    def command_lpwd(self, arguments, command):
623        # Command arguments required   : No
624        # Active SMB connection needed : No
625        # SMB share needed             : No
626
627        self.logger.print(os.getcwd())
def command_lrename(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_lrm(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_lrmdir(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_ltree(self, arguments, command):
681    def command_ltree(self, arguments, command):
682        # Command arguments required   : No
683        # Active SMB connection needed : No
684        # SMB share needed             : No
685
686        if len(arguments) == 0:
687            path = '.'
688        else:
689            path = arguments[0]
690
691        if len(arguments) == 0:
692            local_tree(path='.', config=self.config)
693        else:
694            local_tree(path=path, config=self.config)
def command_ls(*args, **kwargs):
40    def wrapper(*args, **kwargs):
41        self, arguments,command  = args[0], args[1], args[2]
42        #
43        self.sessionsManager.current_session.ping_smb_session()
44        if self.sessionsManager.current_session.connected:
45            return func(*args, **kwargs)
46        else:
47            print("[!] SMB Session is disconnected.")
48            return None
def command_mkdir(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_module(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_mount(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_put(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_reconnect(self, arguments, command):
804    def command_reconnect(self, arguments, command):
805        # Command arguments required   : No
806        # Active SMB connection needed : No
807        # SMB share needed             : No
808
809        self.sessionsManager.current_session.ping_smb_session()
810        if self.sessionsManager.current_session.connected:
811            self.sessionsManager.current_session.close_smb_session()
812            self.sessionsManager.current_session.init_smb_session()
813        else:
814            self.sessionsManager.current_session.init_smb_session()
def command_reset(self, arguments, command):
816    def command_reset(self, arguments, command):
817        # Command arguments required   : No
818        # Active SMB connection needed : No
819        # SMB share needed             : No
820        sys.stdout.write('\x1b[?25h') # Sets the cursor to on
821        sys.stdout.write('\x1b[v')  
822        sys.stdout.write('\x1b[o') # Reset
823        sys.stdout.flush()
def command_rm(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_rmdir(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_sizeof(*args, **kwargs):
40    def wrapper(*args, **kwargs):
41        self, arguments,command  = args[0], args[1], args[2]
42        #
43        self.sessionsManager.current_session.ping_smb_session()
44        if self.sessionsManager.current_session.connected:
45            return func(*args, **kwargs)
46        else:
47            print("[!] SMB Session is disconnected.")
48            return None
def command_shares(*args, **kwargs):
40    def wrapper(*args, **kwargs):
41        self, arguments,command  = args[0], args[1], args[2]
42        #
43        self.sessionsManager.current_session.ping_smb_session()
44        if self.sessionsManager.current_session.connected:
45            return func(*args, **kwargs)
46        else:
47            print("[!] SMB Session is disconnected.")
48            return None
def command_tree(*args, **kwargs):
40    def wrapper(*args, **kwargs):
41        self, arguments,command  = args[0], args[1], args[2]
42        #
43        self.sessionsManager.current_session.ping_smb_session()
44        if self.sessionsManager.current_session.connected:
45            return func(*args, **kwargs)
46        else:
47            print("[!] SMB Session is disconnected.")
48            return None
def command_umount(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None
def command_use(*args, **kwargs):
30    def wrapper(*args, **kwargs):
31        self, arguments,command  = args[0], args[1], args[2]
32        if len(arguments) != 0:
33            return func(*args, **kwargs)
34        else:
35            self.commandCompleterObject.print_help(command=command)
36            return None