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