smbprotocol

repository·master·Indexed 19 days ago

https://github.com/jborean93/smbprotocol

A Python implementation of the SMBv2 and SMBv3 protocols, supporting negotiation from 2.0.2 up to 3.1.1, NTLM/Kerberos authentication, and message encryption. It includes a high-level smbclient interface that replicates Python's built-in os and os.path functions, providing features such as connection pooling, DFS support, and a FileSystemWatcher for monitoring directory changes.

Tokens
18.2K
Snippets
67
Records
77
Agent score
61%

What's inside smbprotocol

  1. Use the smbclient high-level interface

    master

    For most common use cases, use the smbclient interface. It provides a high-level API that replicates Python's built-in os and os.path functions (e.g., mkdir, open_file, stat, exists).

    Key features of smbclient:

    • Connection Pooling: Connections are pooled and reused for the same server during the Python process lifetime.
    • DFS Support: Automatically handles DFS (Distributed File System) targets and caches referrals.
    • Simplified Auth: Authentication is typically only required for the first call to a server.
    import smbclient
    
    # Example usage
    smbclient.mkdir(r"\\server\share\directory", username="user", password="pass")
    
    with smbclient.open_file(r"\\server\share\directory\file.txt", mode="w") as fd:
        fd.write(u"file contents")
  2. Install smbprotocol

    master

    Install the base package using pip:

    pip install smbprotocol

    If you require Kerberos authentication support, install the package with the [kerberos] extra. Note that on Linux, additional system dependencies (like libkrb5-dev) must be installed via your package manager first.

  3. Install smbprotocol with Kerberos support on Linux

    master

    To use Kerberos authentication on Linux, you must install system-level development headers before installing the Python package.

    For Debian/Ubuntu/etc:

    sudo apt-get install gcc python-dev libkrb5-dev
    pip install smbprotocol[kerberos]

    For RHEL/CentOS/etc:

    sudo yum install gcc python-devel krb5-devel krb5-workstation python-devel
    pip install smbprotocol[kerberos]

    You can verify if the required python-gssapi extension is available by running this check in a Python console:

    # for Debian/Ubuntu/etc:
    sudo apt-get install gcc python-dev libkrb5-dev
    pip install smbprotocol[kerberos]
    
    # for RHEL/CentOS/etc:
    sudo yum install gcc python-devel krb5-devel krb5-workstation python-devel
    pip install smbprotocol[kerberos]
  4. Debug smbprotocol with logging

    master
    The library uses Python's built-in logging module. You can inspect logs using the smbprotocol logger or smbprotocol.* for more granular detail. Enabling DEBUG level logging will print human-readable strings of each SMB packet sent by the client, which is useful for deep protocol debugging.
  5. Monitor SMB directory changes with FileSystemWatcher

    master

    The FileSystemWatcher class provides a high-level interface for monitoring changes in an SMB directory. It runs a background thread to listen for server notifications and provides a result property to access the changes once they occur.

    Key Workflow

    1. Initialize: Pass an existing Open() object (representing an open directory) to the FileSystemWatcher constructor.
    2. Start: Call .start() with a completion_filter to specify which types of changes (e.g., file name, attributes) you want to monitor.
    3. Wait/Process: Use .wait() to block until a change is detected, or poll the .result property.
    4. Cancel: Call .cancel() to stop the monitoring request on the server.

    Important Parameters for .start()

    • completion_filter: A bitmask of CompletionFilter constants defining what events trigger a notification.
    • flags: Use ChangeNotifyFlags.SMB2_WATCH_TREE to monitor changes in subdirectories.
    • output_buffer_length: The maximum size of the data returned. Set this to 0 if you only want to know that a change occurred without receiving specific details about which files changed.
    from smbprotocol.change_notify import FileSystemWatcher, CompletionFilter
    
    # Assuming 'directory_open' is an existing smbprotocol Open object
    watcher = FileSystemWatcher(directory_open)
    
    # Start watching for file name and attribute changes
    watcher.start(
        completion_filter=CompletionFilter.FILE_NOTIFY_CHANGE_FILE_NAME | CompletionFilter.FILE_NOTIFY_CHANGE_ATTRIBUTES,
        flags=0x0001  # SMB2_WATCH_TREE
    )
    
    # Wait for a change and get results
    changes = watcher.wait()
    for change in changes:
        print(f"Action: {change.action}, File: {change['file_name']}")
  6. Verify Kerberos availability on Linux

    master

    If you are using Linux, run the following snippet in a Python console to ensure the python-gssapi extension is correctly installed and available. If this fails, the library will fallback to NTLM authentication.

    try:
        from gssapi.raw import inquire_sec_context_by_oid
        print("python-gssapi extension is available")
    except ImportError as exc:
        print(f"python-gssapi extension is not available: {exc}")
  7. Configure global defaults with smbclient.ClientConfig

    master

    The smbclient.ClientConfig singleton allows you to set global connection defaults for all future smbclient calls. Updating the singleton updates the settings for all subsequent operations.

    import smbclient
    
    smbclient.ClientConfig(username='user', password='password')
  8. Manage smbclient connections and sessions

    master

    You can manage how credentials and connections are handled in smbclient using the following methods:

    • Register a session: Use smbclient.register_session("server", username="...", password="...") to associate specific credentials with a server. This overrides the global ClientConfig for that specific server.
    • Reset cache: Use smbclient.reset_connection_cache() to close all currently cached connections.
    import smbclient
    
    # Set global defaults
    smbclient.ClientConfig(username='user', password='pass')
    
    # Register specific credentials for a specific server (overrides ClientConfig)
    smbclient.register_session("server", username="user", password="pass")
    
    # Reset all cached connections
    smbclient.reset_connection_cache()
  9. Set a specific SMB dialect version

    master

    By default, smbprotocol negotiates the latest dialect supported by the server. You can manually override this to set a minimum dialect version using the Connection object and the Dialects enum.

    import uuid
    
    from smbprotocol.connection import Connection, Dialects
    
    connection = Connection(uuid.uuid4(), "server", 445)
    connection.connect(Dialects.SMB_3_0_2)
  10. Reference: smbclient.ClientConfig options

    master

    The following keys can be set on the smbclient.ClientConfig singleton to define global connection behavior:

    • client_guid: The client GUID to identify the client to the server on a new connection.
    • username: The default username to use when creating a new SMB session if explicit credentials weren't set.
    • password: The default password to use for authentication.
    • domain_controller: The domain controller hostname. Useful for DFS environments to identify domain information automatically.
    • skip_dfs: Whether to skip DFS resolution (useful for bypassing bugs or reducing roundtrips).
    • auth_protocol: The authentication protocol to use; options are negotiate (default), kerberos, or ntlm.
    • require_secure_negotiate: Control whether the client validates negotiation info (default: True).
  11. Reference: smbclient function arguments

    master

    Individual smbclient functions (like open_file, mkdir, etc.) accept the following keyword arguments to override global configuration or specify connection parameters:

    • username: The username used to connect to the share.
    • password: The password used to connect to the share.
    • port: Override the default port (445).
    • encrypt: Whether to force encryption on the connection (requires SMBv3+ on the server; default: False).
    • connection_timeout: Override the connection timeout in seconds (default: 60).