smbfs

package module
v0.9.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 12, 2025 License: MIT Imports: 31 Imported by: 0

README

smbfs

Go Reference Go Report Card CI License

SMB/CIFS network filesystem implementation for absfs - access Windows file shares and Samba servers through the absfs.FileSystem interface.

Project Status: ✅ Production Ready | Phase: 4 of 5 (80% Complete) | Stability: Stable

📊 Project Status | 🚀 Deployment Guide | ⚡ Performance Guide | 🔧 Troubleshooting | 🔐 Security Audit

Overview

smbfs provides a complete absfs.FileSystem implementation for SMB/CIFS network shares, enabling seamless access to Windows shares, Samba servers, and other SMB-compatible network storage. It supports modern SMB2/SMB3 protocols with enterprise-grade authentication methods including NTLM, Kerberos, and domain authentication.

Key Features:

  • Full absfs.FileSystem interface compliance
  • SMB2/SMB3/SMB3.1.1 protocol support with automatic dialect negotiation
  • Multiple authentication methods: NTLM, Kerberos, domain, guest access
  • Performance optimizations: Metadata caching, connection pooling, configurable buffers
  • Production ready: Retry logic, timeout handling, comprehensive logging
  • Windows attributes support: Hidden, system, readonly, archive flags
  • Share enumeration: List available shares on SMB servers
  • Security approved: ✅ OWASP Top 10 compliant, no critical vulnerabilities
  • Cross-platform: Windows, Linux, macOS
  • Large file support: Files >4GB fully supported
  • Composable: Works with other absfs implementations (cachefs, metricsfs, etc.)

SMB Protocol Support

Supported Dialects
  • SMB 2.0.2 - Basic SMB2 support
  • SMB 2.1 - Windows 7 / Server 2008 R2
  • SMB 3.0 - Windows 8 / Server 2012 (encryption, multichannel)
  • SMB 3.0.2 - Windows 8.1 / Server 2012 R2
  • SMB 3.1.1 - Windows 10 / Server 2016+ (enhanced security, integrity)
Dialect Negotiation

The implementation automatically negotiates the highest supported dialect with the server:

  1. Client sends list of supported dialects
  2. Server responds with selected dialect
  3. Connection established using negotiated dialect
  4. Fallback to lower dialects if needed

Architecture Design

┌─────────────────────────────────────────┐
│         Application Code                │
└────────────────┬────────────────────────┘
                 │
                 │ absfs.FileSystem interface
                 │
┌────────────────▼────────────────────────┐
│           smbfs.FileSystem              │
│  ┌─────────────────────────────────┐   │
│  │   Connection Pool Manager       │   │
│  │   - Session lifecycle           │   │
│  │   - Connection reuse            │   │
│  │   - Timeout handling            │   │
│  └─────────────────────────────────┘   │
│  ┌─────────────────────────────────┐   │
│  │   Authentication Manager        │   │
│  │   - NTLM authentication         │   │
│  │   - Kerberos integration        │   │
│  │   - Domain credentials          │   │
│  └─────────────────────────────────┘   │
│  ┌─────────────────────────────────┐   │
│  │   File Operations Mapper        │   │
│  │   - Path translation            │   │
│  │   - Attribute mapping           │   │
│  │   - Permission handling         │   │
│  └─────────────────────────────────┘   │
└────────────────┬────────────────────────┘
                 │
                 │ SMB2/SMB3 protocol
                 │
┌────────────────▼────────────────────────┐
│    github.com/hirochachacha/go-smb2    │
│  - Protocol implementation              │
│  - Message encoding/decoding            │
│  - Transport layer (TCP)                │
└────────────────┬────────────────────────┘
                 │
                 │ TCP/IP
                 │
┌────────────────▼────────────────────────┐
│         SMB Server                      │
│  - Windows File Sharing                 │
│  - Samba Server                         │
│  - NAS Devices                          │
└─────────────────────────────────────────┘

Library Integration

Primary library: github.com/hirochachacha/go-smb2

Why go-smb2:

  • Pure Go implementation (no CGO dependencies)
  • SMB2/SMB3 protocol support
  • Active maintenance and updates
  • Cross-platform compatibility
  • Clean API design
  • Good performance characteristics

Alternative considered:

  • github.com/stacktitan/smb - Older, less maintained
  • CGO bindings to libsmbclient - Platform dependency issues

Authentication Methods

Username/Password (NTLM)

Standard NTLM authentication with username and password:

fs, err := smbfs.New(&smbfs.Config{
    Server:   "fileserver.example.com",
    Share:    "shared",
    Username: "jdoe",
    Password: "secret123",
    Domain:   "",  // Optional, for standalone servers
})
Kerberos Authentication

Enterprise Kerberos authentication using system credentials:

fs, err := smbfs.New(&smbfs.Config{
    Server:      "fileserver.corp.example.com",
    Share:       "departments",
    UseKerberos: true,
    Domain:      "CORP",
    Username:    "jdoe",
    // Kerberos ticket used instead of password
})

Requirements:

  • Properly configured /etc/krb5.conf (Linux/macOS)
  • Valid Kerberos ticket (via kinit)
  • DNS resolution for domain controllers
  • System time synchronization (critical for Kerberos)
Guest Access

Anonymous/guest access for public shares:

fs, err := smbfs.New(&smbfs.Config{
    Server:      "public.example.com",
    Share:       "public",
    GuestAccess: true,
})
Domain Authentication

Active Directory domain authentication:

fs, err := smbfs.New(&smbfs.Config{
    Server:   "fileserver.corp.example.com",
    Share:    "departments",
    Username: "jdoe",
    Password: "secret123",
    Domain:   "CORP",  // AD domain
})

Implementation Details

Connection Pooling

Connection pool manages SMB sessions efficiently:

type ConnectionPool struct {
    // Pool configuration
    MaxIdle       int           // Maximum idle connections
    MaxOpen       int           // Maximum open connections
    IdleTimeout   time.Duration // Idle connection timeout
    ConnTimeout   time.Duration // Connection establishment timeout

    // Pool state
    mu          sync.Mutex
    connections []*pooledConn
    waiters     []chan *pooledConn
}

type pooledConn struct {
    conn      *smb2.Session
    share     *smb2.Share
    createdAt time.Time
    lastUsed  time.Time
    inUse     bool
}

Pool behavior:

  • Lazy connection establishment
  • Connection reuse across operations
  • Automatic cleanup of idle connections
  • Graceful handling of server disconnections
  • Thread-safe connection checkout/checkin
Session Management

SMB session lifecycle management:

  1. Connection Establishment

    • TCP connection to server:445
    • SMB dialect negotiation
    • Session setup (authentication)
    • Tree connect to share
  2. Session Maintenance

    • Keep-alive messages
    • Reconnection on timeout
    • Credential refresh (Kerberos)
    • Error recovery
  3. Session Cleanup

    • Tree disconnect
    • Session logoff
    • TCP connection close
    • Resource cleanup
Share Enumeration

List available shares on a server:

type ShareInfo struct {
    Name    string      // Share name
    Type    ShareType   // Disk, Print, IPC, etc.
    Comment string      // Share description
}

func (fs *FileSystem) ListShares(ctx context.Context) ([]ShareInfo, error)

Share types:

  • STYPE_DISKTREE - Disk share (standard file share)
  • STYPE_PRINTQ - Print queue
  • STYPE_DEVICE - Communication device
  • STYPE_IPC - IPC share (named pipes)
  • STYPE_TEMPORARY - Temporary share
  • STYPE_SPECIAL - Special share (admin shares: C$, IPC$, etc.)
File Operations Mapping

Mapping absfs operations to SMB protocol:

absfs Operation SMB2 Command Notes
Open() CREATE With desired access and disposition
OpenFile() CREATE With specific flags mapping
Stat() QUERY_INFO File standard/basic info
ReadDir() QUERY_DIRECTORY With pattern matching
Remove() SET_INFO + DELETE Mark for deletion on close
Rename() SET_INFO Set file name info
Mkdir() CREATE With directory attribute
Chmod() SET_INFO Security descriptor
Chtimes() SET_INFO File basic info
Directory Operations

Efficient directory traversal:

// ReadDir implementation with pagination
func (fs *FileSystem) ReadDir(name string) ([]fs.DirEntry, error) {
    file, err := fs.openDir(name)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    // Use SMB2 QUERY_DIRECTORY with resume
    var entries []fs.DirEntry
    resumeKey := uint32(0)

    for {
        batch, newKey, err := fs.queryDirectory(file, resumeKey)
        if err == io.EOF {
            break
        }
        if err != nil {
            return nil, err
        }

        entries = append(entries, batch...)
        resumeKey = newKey
    }

    return entries, nil
}

Optimizations:

  • Batch directory queries (up to 64KB per request)
  • Resume token handling for large directories
  • Caching of directory metadata
  • Parallel stat operations when needed
Permission Handling (Windows ACLs)

Windows ACL to Unix permission mapping:

type ACLMapper struct {
    // Map Windows SIDs to Unix UIDs/GIDs
    sidToUID map[string]uint32
    sidToGID map[string]uint32

    // Default mappings
    defaultUID uint32
    defaultGID uint32
    defaultMode os.FileMode
}

// Convert Windows security descriptor to Unix mode
func (m *ACLMapper) ACLToMode(sd *SecurityDescriptor) os.FileMode {
    mode := os.FileMode(0)

    // Owner permissions from DACL
    if sd.hasAccess(sd.Owner, FILE_READ_DATA) {
        mode |= 0400
    }
    if sd.hasAccess(sd.Owner, FILE_WRITE_DATA) {
        mode |= 0200
    }
    if sd.hasAccess(sd.Owner, FILE_EXECUTE) {
        mode |= 0100
    }

    // Group and other permissions...

    return mode
}

// Convert Unix mode to Windows security descriptor
func (m *ACLMapper) ModeToACL(mode os.FileMode) *SecurityDescriptor

Permission mapping:

  • Owner → Primary owner SID
  • Group → Primary group SID
  • Other → Everyone SID
  • Read → FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES
  • Write → FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES
  • Execute → FILE_EXECUTE

Configuration Options

type Config struct {
    // Server connection
    Server string // Hostname or IP address
    Port   int    // SMB port (default: 445)
    Share  string // Share name

    // Authentication
    Username    string // Username (domain\user or user@domain)
    Password    string // Password
    Domain      string // Domain name (optional)
    UseKerberos bool   // Use Kerberos authentication
    GuestAccess bool   // Anonymous/guest access

    // SMB protocol
    Dialect     string        // Preferred dialect (SMB2, SMB3, etc.)
    Signing     bool          // Require message signing
    Encryption  bool          // Require encryption (SMB3+)

    // Connection pool
    MaxIdle     int           // Max idle connections (default: 5)
    MaxOpen     int           // Max open connections (default: 10)
    IdleTimeout time.Duration // Idle timeout (default: 5m)
    ConnTimeout time.Duration // Connection timeout (default: 30s)
    OpTimeout   time.Duration // Operation timeout (default: 60s)

    // Behavior
    CaseSensitive bool        // Case-sensitive paths (default: false)
    FollowSymlinks bool       // Follow Windows symlinks/junctions

    // Performance
    ReadBufferSize  int       // Read buffer size (default: 64KB)
    WriteBufferSize int       // Write buffer size (default: 64KB)
    DirectoryCache  bool      // Enable directory metadata caching
    CacheTTL        time.Duration // Cache TTL (default: 30s)
}
Connection String Format

Alternative connection string syntax:

smb://[domain\]username:password@server[:port]/share[/path]
smb://server/share  // Guest access
smb://user:pass@server/share
smb://DOMAIN\user:pass@server/share
smb://server:10445/share  // Non-standard port

Parsing:

func ParseConnectionString(connStr string) (*Config, error) {
    u, err := url.Parse(connStr)
    if err != nil {
        return nil, err
    }

    cfg := &Config{
        Server: u.Hostname(),
        Port:   445, // default
    }

    if u.Port() != "" {
        cfg.Port, _ = strconv.Atoi(u.Port())
    }

    // Extract share from path
    parts := strings.Split(strings.TrimPrefix(u.Path, "/"), "/")
    if len(parts) > 0 {
        cfg.Share = parts[0]
    }

    // Extract credentials
    if u.User != nil {
        username := u.User.Username()
        if password, ok := u.User.Password(); ok {
            cfg.Password = password
        }

        // Handle domain\user format
        if strings.Contains(username, "\\") {
            parts := strings.SplitN(username, "\\", 2)
            cfg.Domain = parts[0]
            cfg.Username = parts[1]
        } else {
            cfg.Username = username
        }
    }

    return cfg, nil
}

Technical Specifications

SMB Dialect Negotiation
type DialectNegotiator struct {
    preferredDialects []uint16
    requiredFeatures  uint32
}

// Dialect constants
const (
    DialectSmb202  = 0x0202  // SMB 2.0.2
    DialectSmb21   = 0x0210  // SMB 2.1
    DialectSmb30   = 0x0300  // SMB 3.0
    DialectSmb302  = 0x0302  // SMB 3.0.2
    DialectSmb311  = 0x0311  // SMB 3.1.1
)

// Feature flags
const (
    FeatureDFS         = 0x00000001
    FeatureLeasing     = 0x00000002
    FeatureLargeMTU    = 0x00000004
    FeatureMultiChannel = 0x00000008
    FeaturePersistent  = 0x00000010
    FeatureDirectory   = 0x00000020
    FeatureEncryption  = 0x00000040
)

func (dn *DialectNegotiator) Negotiate(ctx context.Context, conn net.Conn) (uint16, error) {
    // Send negotiate request with supported dialects
    req := &NegotiateRequest{
        Dialects: dn.preferredDialects,
        SecurityMode: NEGOTIATE_SIGNING_ENABLED,
        Capabilities: dn.requiredFeatures,
    }

    // Receive negotiate response
    resp, err := sendNegotiate(ctx, conn, req)
    if err != nil {
        return 0, err
    }

    // Validate selected dialect
    selectedDialect := resp.DialectRevision
    if !contains(dn.preferredDialects, selectedDialect) {
        return 0, ErrUnsupportedDialect
    }

    return selectedDialect, nil
}
Credential Management
Environment Variables
# Basic authentication
export SMB_USERNAME="jdoe"
export SMB_PASSWORD="secret123"
export SMB_DOMAIN="CORP"

# Kerberos
export SMB_USE_KERBEROS="true"
export KRB5_CONFIG="/etc/krb5.conf"
export KRB5CCNAME="/tmp/krb5cc_1000"

# Server configuration
export SMB_SERVER="fileserver.example.com"
export SMB_SHARE="shared"
Configuration File

~/.config/smbfs/config.yaml:

servers:
  - name: corporate
    server: fileserver.corp.example.com
    domain: CORP
    username: jdoe
    # Password in keyring or separate credentials file
    use_kerberos: true
    shares:
      - name: departments
        path: /
      - name: home
        path: /home/jdoe

  - name: nas
    server: nas.home.local
    username: admin
    # Password in keyring
    shares:
      - name: media
        path: /media
      - name: backups
        path: /backups

# Global settings
connection_pool:
  max_idle: 5
  max_open: 10
  idle_timeout: 5m

security:
  require_signing: true
  require_encryption: false
  min_dialect: SMB3

Credentials file ~/.config/smbfs/credentials:

[corporate]
username=jdoe
password=secret123

[nas]
username=admin
password=nasadmin123

Security:

  • Credentials file should be mode 0600
  • Support system keyring integration (keychain, gnome-keyring, etc.)
  • Never log passwords
  • Clear password from memory after use
Share Path Handling

Normalize different path formats:

type PathNormalizer struct {
    separator rune
    caseSensitive bool
}

// Support multiple formats:
// Windows: \\server\share\path\to\file
// Unix-style: /server/share/path/to/file
// SMB URL: smb://server/share/path/to/file
func (pn *PathNormalizer) Normalize(path string) string {
    // Convert Windows separators
    path = strings.ReplaceAll(path, "\\", "/")

    // Remove leading // or \\
    path = strings.TrimPrefix(path, "//")

    // Remove server and share components (already in connection)
    parts := strings.Split(path, "/")
    if len(parts) >= 2 {
        // Skip server and share parts
        path = "/" + strings.Join(parts[2:], "/")
    }

    // Clean path
    path = filepath.Clean(path)

    // Case normalization (Windows is case-insensitive)
    if !pn.caseSensitive {
        path = strings.ToLower(path)
    }

    return path
}
Windows-Specific File Attributes
// Windows file attribute flags
const (
    FILE_ATTRIBUTE_READONLY            = 0x00000001
    FILE_ATTRIBUTE_HIDDEN              = 0x00000002
    FILE_ATTRIBUTE_SYSTEM              = 0x00000004
    FILE_ATTRIBUTE_DIRECTORY           = 0x00000010
    FILE_ATTRIBUTE_ARCHIVE             = 0x00000020
    FILE_ATTRIBUTE_DEVICE              = 0x00000040
    FILE_ATTRIBUTE_NORMAL              = 0x00000080
    FILE_ATTRIBUTE_TEMPORARY           = 0x00000100
    FILE_ATTRIBUTE_SPARSE_FILE         = 0x00000200
    FILE_ATTRIBUTE_REPARSE_POINT       = 0x00000400
    FILE_ATTRIBUTE_COMPRESSED          = 0x00000800
    FILE_ATTRIBUTE_OFFLINE             = 0x00001000
    FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000
    FILE_ATTRIBUTE_ENCRYPTED           = 0x00004000
)

type WindowsAttributes struct {
    Attributes uint32
}

func (wa *WindowsAttributes) IsHidden() bool {
    return wa.Attributes & FILE_ATTRIBUTE_HIDDEN != 0
}

func (wa *WindowsAttributes) IsSystem() bool {
    return wa.Attributes & FILE_ATTRIBUTE_SYSTEM != 0
}

func (wa *WindowsAttributes) IsReadOnly() bool {
    return wa.Attributes & FILE_ATTRIBUTE_READONLY != 0
}

// Extended file info with Windows attributes
type FileInfoWithAttrs struct {
    fs.FileInfo
    WinAttrs *WindowsAttributes
}
Opportunistic Locking (Oplocks)
// Oplock levels
const (
    OPLOCK_LEVEL_NONE       = 0x00
    OPLOCK_LEVEL_II         = 0x01  // Shared oplock
    OPLOCK_LEVEL_EXCLUSIVE  = 0x08  // Exclusive oplock
    OPLOCK_LEVEL_BATCH      = 0x09  // Batch oplock
    OPLOCK_LEVEL_LEASE      = 0xFF  // SMB3 lease (durable)
)

type OplockManager struct {
    mu      sync.Mutex
    oplocks map[uint64]*Oplock  // File ID -> Oplock
}

type Oplock struct {
    FileID      uint64
    Level       uint8
    BreakNotify chan struct{}
}

// Request oplock on file open
func (om *OplockManager) RequestOplock(fileID uint64, level uint8) (*Oplock, error) {
    oplock := &Oplock{
        FileID:      fileID,
        Level:       level,
        BreakNotify: make(chan struct{}, 1),
    }

    om.mu.Lock()
    om.oplocks[fileID] = oplock
    om.mu.Unlock()

    return oplock, nil
}

// Handle oplock break notification from server
func (om *OplockManager) HandleBreak(fileID uint64, newLevel uint8) {
    om.mu.Lock()
    oplock, exists := om.oplocks[fileID]
    om.mu.Unlock()

    if !exists {
        return
    }

    // Notify application of break
    select {
    case oplock.BreakNotify <- struct{}{}:
    default:
    }

    // Flush cached data, acknowledge break, etc.
}

Oplock benefits:

  • Reduced server round-trips for cached data
  • Client-side caching of file data and metadata
  • Better performance for read-heavy workloads
  • Automatic cache invalidation on server changes
Large File Support (>4GB)
// Ensure 64-bit file operations
type LargeFileSupport struct {
    capabilities uint32
}

const (
    CAP_LARGE_FILES     = 0x00000008
    CAP_LARGE_READX     = 0x00004000
    CAP_LARGE_WRITEX    = 0x00008000
)

func (lfs *LargeFileSupport) MaxReadSize() int64 {
    if lfs.capabilities & CAP_LARGE_READX != 0 {
        return 16 * 1024 * 1024  // 16MB max read
    }
    return 64 * 1024  // 64KB standard
}

func (lfs *LargeFileSupport) MaxWriteSize() int64 {
    if lfs.capabilities & CAP_LARGE_WRITEX != 0 {
        return 16 * 1024 * 1024  // 16MB max write
    }
    return 64 * 1024  // 64KB standard
}

// Split large I/O into chunks
func (f *File) Read(p []byte) (n int, err error) {
    maxChunk := f.fs.largeFile.MaxReadSize()

    for n < len(p) {
        chunkSize := min(int64(len(p)-n), maxChunk)

        chunk, err := f.readChunk(f.offset+int64(n), int(chunkSize))
        if err != nil {
            if err == io.EOF && n > 0 {
                return n, nil
            }
            return n, err
        }

        copy(p[n:], chunk)
        n += len(chunk)

        if len(chunk) < int(chunkSize) {
            return n, io.EOF
        }
    }

    return n, nil
}
Error Handling and Retry Logic
type RetryPolicy struct {
    MaxAttempts int
    InitialDelay time.Duration
    MaxDelay     time.Duration
    Multiplier   float64
}

var defaultRetryPolicy = RetryPolicy{
    MaxAttempts:  3,
    InitialDelay: 100 * time.Millisecond,
    MaxDelay:     5 * time.Second,
    Multiplier:   2.0,
}

// Retryable error types
func isRetryable(err error) bool {
    if err == nil {
        return false
    }

    // Network errors are retryable
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Temporary() {
        return true
    }

    // SMB status codes that are retryable
    var smbErr *SMBError
    if errors.As(err, &smbErr) {
        switch smbErr.Status {
        case STATUS_NETWORK_NAME_DELETED,
             STATUS_CONNECTION_DISCONNECTED,
             STATUS_CONNECTION_RESET,
             STATUS_INSUFF_SERVER_RESOURCES:
            return true
        }
    }

    return false
}

func (fs *FileSystem) withRetry(ctx context.Context, op func() error) error {
    policy := fs.config.RetryPolicy
    if policy == nil {
        policy = &defaultRetryPolicy
    }

    var lastErr error
    delay := policy.InitialDelay

    for attempt := 0; attempt < policy.MaxAttempts; attempt++ {
        // Check context cancellation
        if ctx.Err() != nil {
            return ctx.Err()
        }

        // Attempt operation
        err := op()
        if err == nil {
            return nil
        }

        lastErr = err

        // Don't retry if error is not retryable
        if !isRetryable(err) {
            return err
        }

        // Don't retry on last attempt
        if attempt == policy.MaxAttempts-1 {
            break
        }

        // Exponential backoff
        select {
        case <-ctx.Done():
            return ctx.Err()
        case <-time.After(delay):
        }

        delay = time.Duration(float64(delay) * policy.Multiplier)
        if delay > policy.MaxDelay {
            delay = policy.MaxDelay
        }
    }

    return lastErr
}
Timeout Configuration
type TimeoutConfig struct {
    // Connection timeouts
    ConnectTimeout time.Duration  // TCP connection (default: 30s)
    NegotiateTimeout time.Duration // Dialect negotiation (default: 10s)
    AuthTimeout time.Duration      // Authentication (default: 30s)

    // Operation timeouts
    ReadTimeout  time.Duration     // Read operations (default: 60s)
    WriteTimeout time.Duration     // Write operations (default: 60s)
    StatTimeout  time.Duration     // Metadata operations (default: 10s)

    // Session timeouts
    IdleTimeout    time.Duration   // Idle connection (default: 5m)
    SessionTimeout time.Duration   // Total session lifetime (default: 24h)
    KeepAlive      time.Duration   // Keep-alive interval (default: 60s)
}

// Apply timeout to context
func (tc *TimeoutConfig) withTimeout(ctx context.Context, op string) (context.Context, context.CancelFunc) {
    var timeout time.Duration

    switch op {
    case "read":
        timeout = tc.ReadTimeout
    case "write":
        timeout = tc.WriteTimeout
    case "stat":
        timeout = tc.StatTimeout
    default:
        timeout = tc.ReadTimeout  // default
    }

    return context.WithTimeout(ctx, timeout)
}

Implementation Phases

Phase 1: Core Infrastructure
  • SMB client library integration (go-smb2)
  • Connection management and pooling
  • Basic authentication (username/password, NTLM)
  • Session lifecycle management
  • Configuration parsing and validation
  • Error handling framework
Phase 2: Basic File Operations
  • File open/close/read/write
  • File stat and metadata
  • Basic directory operations (ReadDir, Mkdir, Remove)
  • Path normalization and validation
  • absfs.FileSystem interface implementation
  • Unit tests for core operations
Phase 3: Advanced Features
  • Advanced authentication (Kerberos, domain)
  • Permission handling (ACL mapping)
  • Windows attribute support
  • Oplock management
  • Large file support (>4GB)
  • Share enumeration
Phase 4: Performance Optimization
  • Connection pooling optimization
  • Directory metadata caching
  • Parallel operations where possible
  • Buffer size tuning
  • Batch operations
  • Performance benchmarking
Phase 5: Production Readiness
  • Comprehensive error handling
  • Retry logic and resilience
  • Timeout configuration
  • Logging and debugging
  • Integration tests
  • Documentation and examples
  • Security audit

Usage Examples

Connect to Windows Share
package main

import (
    "context"
    "fmt"
    "io/fs"
    "log"

    "github.com/absfs/smbfs"
)

func main() {
    // Connect to Windows file share
    fsys, err := smbfs.New(&smbfs.Config{
        Server:   "fileserver.corp.example.com",
        Share:    "departments",
        Username: "jdoe",
        Password: "secret123",
        Domain:   "CORP",
    })
    if err != nil {
        log.Fatal(err)
    }
    defer fsys.Close()

    // List files in engineering directory
    entries, err := fs.ReadDir(fsys, "/engineering")
    if err != nil {
        log.Fatal(err)
    }

    for _, entry := range entries {
        info, _ := entry.Info()
        fmt.Printf("%s %10d %s\n",
            info.Mode(),
            info.Size(),
            entry.Name())
    }

    // Read a file
    data, err := fs.ReadFile(fsys, "/engineering/specs/design.pdf")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Read %d bytes\n", len(data))
}
Connect to Samba Server
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/absfs/smbfs"
)

func main() {
    // Connect to Samba server (Linux/Unix)
    fsys, err := smbfs.New(&smbfs.Config{
        Server:   "nas.home.local",
        Share:    "media",
        Username: "homeuser",
        Password: "homepass",
        // No domain needed for Samba workgroup
    })
    if err != nil {
        log.Fatal(err)
    }
    defer fsys.Close()

    // Upload a video file
    ctx := context.Background()
    src, err := os.Open("/local/videos/movie.mp4")
    if err != nil {
        log.Fatal(err)
    }
    defer src.Close()

    dst, err := fsys.OpenFile("/videos/uploaded/movie.mp4",
        os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer dst.Close()

    written, err := io.Copy(dst, src)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Uploaded %d bytes\n", written)
}
Domain-Joined Authentication
package main

import (
    "log"
    "os"

    "github.com/absfs/smbfs"
)

func main() {
    // Use Kerberos authentication (requires kinit)
    fsys, err := smbfs.New(&smbfs.Config{
        Server:      "fileserver.corp.example.com",
        Share:       "home",
        UseKerberos: true,
        Domain:      "CORP",
        Username:    os.Getenv("USER"),
    })
    if err != nil {
        log.Fatal(err)
    }
    defer fsys.Close()

    // Access home directory with Kerberos ticket
    // No password needed - uses Kerberos ticket cache

    entries, err := fsys.ReadDir("/")
    if err != nil {
        log.Fatal(err)
    }

    for _, entry := range entries {
        log.Printf("  %s\n", entry.Name())
    }
}
Composition with cachefs for Performance
package main

import (
    "log"
    "time"

    "github.com/absfs/absfs"
    "github.com/absfs/cachefs"
    "github.com/absfs/smbfs"
    "github.com/absfs/memfs"
)

func main() {
    // Create SMB filesystem
    remote, err := smbfs.New(&smbfs.Config{
        Server:   "fileserver.corp.example.com",
        Share:    "projects",
        Username: "jdoe",
        Password: "secret123",
        Domain:   "CORP",
    })
    if err != nil {
        log.Fatal(err)
    }
    defer remote.Close()

    // Create in-memory cache
    cache := memfs.New()

    // Compose with cachefs for better performance
    fsys, err := cachefs.New(&cachefs.Config{
        Remote: remote,
        Cache:  cache,
        TTL:    5 * time.Minute,
        // Cache metadata and small files
        MaxCacheSize: 100 * 1024 * 1024, // 100MB
        CachePolicy:  cachefs.PolicyLRU,
    })
    if err != nil {
        log.Fatal(err)
    }
    defer fsys.Close()

    // Now operations are cached
    // First read hits network
    data1, _ := fs.ReadFile(fsys, "/project/README.md")

    // Second read hits cache (much faster)
    data2, _ := fs.ReadFile(fsys, "/project/README.md")

    log.Printf("Read %d bytes (cached: %d)\n", len(data1), len(data2))
}

Platform Support

smbfs is a cross-platform SMB client implementation:

Supported Platforms:

  • Linux - Full support, native performance
  • macOS - Full support, native performance
  • Windows - Full support (alternative to built-in SMB)
  • FreeBSD - Full support with go-smb2
  • Other Unix - Should work on any platform with Go support

Platform-Specific Features:

  • Linux: Integration with system Kerberos (krb5.conf)
  • macOS: Keychain integration for credential storage
  • Windows: Can use Windows credential manager
  • All: Pure Go implementation, no CGO required

Advantages over OS-native SMB:

  • Consistent behavior across platforms
  • No dependency on OS SMB stack
  • Programmatic control over connection parameters
  • Better error handling and debugging
  • Composable with other absfs implementations

Performance Considerations

Network Latency
  • High latency impacts small operations (stat, readdir)
  • Use caching (cachefs) for metadata-heavy workloads
  • Batch operations when possible
  • Consider directory caching for repeated scans
Bandwidth Optimization
  • Large buffer sizes for sequential I/O (default: 64KB)
  • Connection reuse via pooling
  • Parallel transfers for multiple files
  • SMB3 multichannel support (future)
Connection Pooling
  • Shared connections reduce auth overhead
  • Idle timeout prevents resource exhaustion
  • Max connections limit controls server load
  • Thread-safe connection management
Caching Strategies
  • Metadata caching (file info, directory listings)
  • Read-ahead for sequential access
  • Write-behind for improved write performance
  • Oplock-based cache coherency

Benchmarking:

// Benchmark sequential reads
func BenchmarkSequentialRead(b *testing.B) {
    fsys := setupSMBFS()
    defer fsys.Close()

    f, _ := fsys.Open("/testfile")
    defer f.Close()

    buf := make([]byte, 64*1024)
    b.ResetTimer()

    for i := 0; i < b.N; i++ {
        f.Read(buf)
    }
}

// Benchmark with vs without caching
func BenchmarkCachedVsUncached(b *testing.B) {
    // Test both scenarios
}

Testing Strategy

Unit Tests
  • Connection management
  • Authentication methods
  • Path normalization
  • Error handling
  • Configuration parsing
  • Pool behavior
Integration Tests
  • Real SMB server connectivity
  • File operations (CRUD)
  • Directory operations
  • Large file transfers
  • Concurrent operations
  • Session recovery
Test Infrastructure
// Test server setup
type TestSMBServer struct {
    Server   string
    Share    string
    Username string
    Password string
}

func SetupTestServer(t *testing.T) *TestSMBServer {
    // Use Docker to run Samba container
    // Or connect to pre-configured test server
}

func TestBasicOperations(t *testing.T) {
    srv := SetupTestServer(t)

    fsys, err := smbfs.New(&smbfs.Config{
        Server:   srv.Server,
        Share:    srv.Share,
        Username: srv.Username,
        Password: srv.Password,
    })
    require.NoError(t, err)
    defer fsys.Close()

    // Test file creation
    f, err := fsys.Create("/test.txt")
    require.NoError(t, err)

    _, err = f.Write([]byte("hello world"))
    require.NoError(t, err)

    f.Close()

    // Test file reading
    data, err := fs.ReadFile(fsys, "/test.txt")
    require.NoError(t, err)
    assert.Equal(t, "hello world", string(data))

    // Test file deletion
    err = fsys.Remove("/test.txt")
    require.NoError(t, err)
}
Compatibility Testing
  • Windows Server (2012, 2016, 2019, 2022)
  • Samba versions (4.x)
  • NAS devices (Synology, QNAP, etc.)
  • Different SMB dialects
  • Various authentication methods
Performance Testing
  • Throughput benchmarks
  • Latency measurements
  • Connection pool efficiency
  • Cache effectiveness
  • Concurrent operation scaling

Comparison with Other Network Filesystems

Feature smbfs webdavfs sftpfs httpfs
Protocol SMB/CIFS WebDAV SSH/SFTP HTTP/HTTPS
Primary Use Windows shares Web storage SSH servers Web servers
Authentication NTLM, Kerberos, Domain Basic, Digest, OAuth SSH keys, password Basic, Bearer
Write Support Full Full Full Limited
Performance High (LAN) Medium Medium Medium
Firewall Friendly Port 445 (often blocked) Port 80/443 (open) Port 22 (often open) Port 80/443 (open)
Windows Integration Native Good Limited Limited
Unix Integration Good Good Native Limited
Large Files Excellent Good Good Limited
Encryption SMB3+ TLS SSH TLS
Permissions Windows ACL WebDAV ACL Unix permissions Limited
Locking Oplocks WebDAV locks Advisory None
Caching Client-side Client-side Limited ETags

When to use smbfs:

  • Accessing Windows file shares
  • Corporate network file storage
  • Samba servers in mixed environments
  • NAS devices with SMB support
  • Integration with Active Directory
  • High-performance LAN file access

When to use alternatives:

  • webdavfs: Internet-accessible storage, cloud services
  • sftpfs: SSH-enabled servers, Unix environments
  • httpfs: Read-only web content, static files

Composition patterns:

// SMB with caching for WAN scenarios
cachedSMB := cachefs.New(smbfs.New(...), memfs.New())

// SMB with retry for unreliable networks
resilientSMB := retryfs.New(smbfs.New(...))

// SMB with metrics for monitoring
monitoredSMB := metricsfs.New(smbfs.New(...))

// SMB with encryption layer (additional to SMB3 encryption)
securedSMB := encryptfs.New(smbfs.New(...))

Security Considerations

Network Security
  • Always use SMB3+ with encryption for untrusted networks
  • Enable message signing to prevent tampering
  • Use VPN for Internet-exposed SMB servers
  • Avoid SMB1 (disabled by default)
Credential Security
  • Store credentials in system keyring, not plaintext
  • Use Kerberos for domain environments (no password transmission)
  • Rotate passwords regularly
  • Use least-privilege accounts
Access Control
  • Respect Windows ACLs
  • Map permissions appropriately
  • Audit access logs
  • Implement client-side validation
Attack Mitigation
  • Rate limiting for failed authentication
  • Connection timeout to prevent resource exhaustion
  • Input validation for paths and filenames
  • Protection against path traversal

License

MIT License - see LICENSE file for details

Contributing

Contributions welcome! Please see CONTRIBUTING.md for guidelines.

Documentation

Getting Started
Operations & Deployment
Reference

Support

Documentation

Overview

Package smbfs provides an SMB/CIFS network filesystem implementation for absfs - access Windows file shares and Samba servers through the absfs.FileSystem interface.

Overview

smbfs enables seamless access to SMB network shares with full support for the absfs.FileSystem interface. It supports SMB2, SMB3, and SMB3.1.1 protocols with enterprise-grade authentication including NTLM, Kerberos, and domain authentication.

Features

  • Full absfs.FileSystem interface compliance
  • SMB2, SMB3, and SMB3.1.1 protocol support
  • Multiple authentication methods (NTLM, Kerberos, domain, guest)
  • Connection pooling and session management
  • Cross-platform SMB client (Windows, Linux, macOS)
  • Large file support (>4GB)
  • Composable with other absfs implementations

Basic Usage

Connect to an SMB share with username/password:

fs, err := smbfs.New(&smbfs.Config{
    Server:   "fileserver.example.com",
    Share:    "shared",
    Username: "jdoe",
    Password: "secret123",
})
if err != nil {
    log.Fatal(err)
}
defer fs.Close()

// Use standard file operations
data, err := fs.ReadFile("/path/to/file.txt")

Connection String

Alternatively, use a connection string:

fs, err := smbfs.ParseConnectionString("smb://user:pass@server/share")

Authentication Methods

Username/Password (NTLM):

&smbfs.Config{
    Server:   "fileserver.example.com",
    Share:    "shared",
    Username: "jdoe",
    Password: "secret123",
    Domain:   "CORP",  // Optional for domain-joined servers
}

Kerberos Authentication:

&smbfs.Config{
    Server:      "fileserver.corp.example.com",
    Share:       "departments",
    UseKerberos: true,
    Domain:      "CORP",
    Username:    "jdoe",
}

Guest Access:

&smbfs.Config{
    Server:      "public.example.com",
    Share:       "public",
    GuestAccess: true,
}

Configuration

The Config structure provides extensive customization options:

  • Server connection (server, port, share)
  • Authentication (username, password, domain, Kerberos)
  • Connection pooling (max idle/open, timeouts)
  • Performance tuning (buffer sizes, caching)

Composition

smbfs can be composed with other absfs implementations:

// Add caching for better performance
cached := cachefs.New(smbfs.New(...), memfs.New())

// Add metrics for monitoring
monitored := metricsfs.New(smbfs.New(...))

Platform Support

smbfs works on all platforms supported by Go:

  • Linux (native performance)
  • macOS (native performance)
  • Windows (alternative to built-in SMB)
  • FreeBSD and other Unix systems

Pure Go implementation with no CGO dependencies.

Index

Constants

View Source
const (
	// FILE_ATTRIBUTE_READONLY indicates the file is read-only.
	FILE_ATTRIBUTE_READONLY = 0x00000001

	// FILE_ATTRIBUTE_HIDDEN indicates the file is hidden.
	FILE_ATTRIBUTE_HIDDEN = 0x00000002

	// FILE_ATTRIBUTE_SYSTEM indicates the file is a system file.
	FILE_ATTRIBUTE_SYSTEM = 0x00000004

	// FILE_ATTRIBUTE_DIRECTORY indicates the file is a directory.
	FILE_ATTRIBUTE_DIRECTORY = 0x00000010

	// FILE_ATTRIBUTE_ARCHIVE indicates the file should be archived.
	FILE_ATTRIBUTE_ARCHIVE = 0x00000020

	// FILE_ATTRIBUTE_DEVICE indicates the file is a device.
	FILE_ATTRIBUTE_DEVICE = 0x00000040

	// FILE_ATTRIBUTE_NORMAL indicates the file has no other attributes set.
	FILE_ATTRIBUTE_NORMAL = 0x00000080

	// FILE_ATTRIBUTE_TEMPORARY indicates the file is temporary.
	FILE_ATTRIBUTE_TEMPORARY = 0x00000100

	// FILE_ATTRIBUTE_SPARSE_FILE indicates the file is a sparse file.
	FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200

	// FILE_ATTRIBUTE_REPARSE_POINT indicates the file is a reparse point (symlink/junction).
	FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400

	// FILE_ATTRIBUTE_COMPRESSED indicates the file is compressed.
	FILE_ATTRIBUTE_COMPRESSED = 0x00000800

	// FILE_ATTRIBUTE_OFFLINE indicates the file data is offline.
	FILE_ATTRIBUTE_OFFLINE = 0x00001000

	// FILE_ATTRIBUTE_NOT_CONTENT_INDEXED indicates the file should not be indexed.
	FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000

	// FILE_ATTRIBUTE_ENCRYPTED indicates the file is encrypted.
	FILE_ATTRIBUTE_ENCRYPTED = 0x00004000
)

Windows file attribute flags as defined in MS-FSCC.

View Source
const (
	SMB2_NEGOTIATE       uint16 = 0x0000
	SMB2_SESSION_SETUP   uint16 = 0x0001
	SMB2_LOGOFF          uint16 = 0x0002
	SMB2_TREE_CONNECT    uint16 = 0x0003
	SMB2_TREE_DISCONNECT uint16 = 0x0004
	SMB2_CREATE          uint16 = 0x0005
	SMB2_CLOSE           uint16 = 0x0006
	SMB2_FLUSH           uint16 = 0x0007
	SMB2_READ            uint16 = 0x0008
	SMB2_WRITE           uint16 = 0x0009
	SMB2_LOCK            uint16 = 0x000A
	SMB2_IOCTL           uint16 = 0x000B
	SMB2_CANCEL          uint16 = 0x000C
	SMB2_ECHO            uint16 = 0x000D
	SMB2_QUERY_DIRECTORY uint16 = 0x000E
	SMB2_CHANGE_NOTIFY   uint16 = 0x000F
	SMB2_QUERY_INFO      uint16 = 0x0010
	SMB2_SET_INFO        uint16 = 0x0011
	SMB2_OPLOCK_BREAK    uint16 = 0x0012
)

SMB2 Command opcodes

View Source
const (
	SMB2_RESTART_SCANS       uint8 = 0x01 // Restart directory enumeration
	SMB2_RETURN_SINGLE_ENTRY uint8 = 0x02 // Return only one entry
	SMB2_INDEX_SPECIFIED     uint8 = 0x04 // Start at FileIndex
	SMB2_REOPEN              uint8 = 0x10 // Reopen directory handle
)

SMB2 QUERY_DIRECTORY flags

View Source
const (
	// File system control codes
	FSCTL_DFS_GET_REFERRALS            uint32 = 0x00060194
	FSCTL_DFS_GET_REFERRALS_EX         uint32 = 0x000601B0
	FSCTL_PIPE_PEEK                    uint32 = 0x0011400C
	FSCTL_PIPE_WAIT                    uint32 = 0x00110018
	FSCTL_PIPE_TRANSCEIVE              uint32 = 0x0011C017
	FSCTL_SRV_COPYCHUNK                uint32 = 0x001440F2
	FSCTL_SRV_ENUMERATE_SNAPSHOTS      uint32 = 0x00144064
	FSCTL_SRV_REQUEST_RESUME_KEY       uint32 = 0x00140078
	FSCTL_SRV_READ_HASH                uint32 = 0x001441BB
	FSCTL_SRV_COPYCHUNK_WRITE          uint32 = 0x001480F2
	FSCTL_LMR_REQUEST_RESILIENCY       uint32 = 0x001401D4
	FSCTL_QUERY_NETWORK_INTERFACE_INFO uint32 = 0x001401FC
	FSCTL_SET_REPARSE_POINT            uint32 = 0x000900A4
	FSCTL_GET_REPARSE_POINT            uint32 = 0x000900A8
	FSCTL_VALIDATE_NEGOTIATE_INFO      uint32 = 0x00140204
)

IOCTL control codes

View Source
const (
	SMB2_PREAUTH_INTEGRITY_CAPABILITIES uint16 = 0x0001
	SMB2_ENCRYPTION_CAPABILITIES        uint16 = 0x0002
	SMB2_SIGNING_CAPABILITIES           uint16 = 0x0008
)

SMB 3.1.1 Negotiate Context Types

View Source
const (
	SMB2_ENCRYPTION_AES128_CCM uint16 = 0x0001
	SMB2_ENCRYPTION_AES128_GCM uint16 = 0x0002
)

SMB 3.1.1 Cipher IDs

View Source
const (
	SMB2_SIGNING_AES_CMAC    uint16 = 0x0001
	SMB2_SIGNING_AES_GMAC    uint16 = 0x0002
	SMB2_SIGNING_HMAC_SHA256 uint16 = 0x0000 // For SMB 3.0.x compatibility
)

SMB 3.1.1 Signing Algorithm IDs

View Source
const (
	SMB2_SESSION_FLAG_IS_GUEST uint16 = 0x0001 // Session is guest
	SMB2_SESSION_FLAG_IS_NULL  uint16 = 0x0002 // Session is null (anonymous)
	SMB2_SESSION_FLAG_ENCRYPT  uint16 = 0x0004 // Session requires encryption
)

SMB2 Session Flags (in response)

View Source
const (
	SignatureOffset = 48
	SignatureLength = 16
)

SMB2 signature field is at offset 48 in the SMB2 header (16 bytes)

View Source
const (
	// SMB2 protocol signature
	SMB2ProtocolID = "\xFESMB"

	// SMB2 header size
	SMB2HeaderSize = 64

	// Maximum sizes
	MaxTransactSize = 8 * 1024 * 1024 // 8MB
	MaxReadSize     = 8 * 1024 * 1024 // 8MB
	MaxWriteSize    = 8 * 1024 * 1024 // 8MB
	MaxBufferSize   = 64 * 1024       // 64KB default buffer
)

SMB2 Protocol constants

View Source
const (
	SMB2_FLAGS_SERVER_TO_REDIR    uint32 = 0x00000001 // Response flag
	SMB2_FLAGS_ASYNC_COMMAND      uint32 = 0x00000002
	SMB2_FLAGS_RELATED_OPERATIONS uint32 = 0x00000004 // Compound request
	SMB2_FLAGS_SIGNED             uint32 = 0x00000008 // Message is signed
	SMB2_FLAGS_PRIORITY_MASK      uint32 = 0x00000070
	SMB2_FLAGS_DFS_OPERATIONS     uint32 = 0x10000000
	SMB2_FLAGS_REPLAY_OPERATION   uint32 = 0x20000000
)

SMB2 Header flags

View Source
const (
	FILE_READ_DATA         uint32 = 0x00000001
	FILE_WRITE_DATA        uint32 = 0x00000002
	FILE_APPEND_DATA       uint32 = 0x00000004
	FILE_READ_EA           uint32 = 0x00000008
	FILE_WRITE_EA          uint32 = 0x00000010
	FILE_EXECUTE           uint32 = 0x00000020
	FILE_DELETE_CHILD      uint32 = 0x00000040
	FILE_READ_ATTRIBUTES   uint32 = 0x00000080
	FILE_WRITE_ATTRIBUTES  uint32 = 0x00000100
	DELETE                 uint32 = 0x00010000
	READ_CONTROL           uint32 = 0x00020000
	WRITE_DAC              uint32 = 0x00040000
	WRITE_OWNER            uint32 = 0x00080000
	SYNCHRONIZE            uint32 = 0x00100000
	ACCESS_SYSTEM_SECURITY uint32 = 0x01000000
	MAXIMUM_ALLOWED        uint32 = 0x02000000
	GENERIC_ALL            uint32 = 0x10000000
	GENERIC_EXECUTE        uint32 = 0x20000000
	GENERIC_WRITE          uint32 = 0x40000000
	GENERIC_READ           uint32 = 0x80000000
)

SMB2 Access Mask (desired access rights)

View Source
const (
	FILE_SHARE_READ   uint32 = 0x00000001
	FILE_SHARE_WRITE  uint32 = 0x00000002
	FILE_SHARE_DELETE uint32 = 0x00000004
)

SMB2 Share Access

View Source
const (
	FILE_SUPERSEDE    uint32 = 0x00000000 // If exists, replace; if not, create
	FILE_OPEN         uint32 = 0x00000001 // Open existing file
	FILE_CREATE       uint32 = 0x00000002 // Create new file; fail if exists
	FILE_OPEN_IF      uint32 = 0x00000003 // Open if exists; create if not
	FILE_OVERWRITE    uint32 = 0x00000004 // Open and overwrite; fail if not exists
	FILE_OVERWRITE_IF uint32 = 0x00000005 // Open and overwrite; create if not
)

SMB2 Create Disposition

View Source
const (
	FILE_DIRECTORY_FILE            uint32 = 0x00000001
	FILE_WRITE_THROUGH             uint32 = 0x00000002
	FILE_SEQUENTIAL_ONLY           uint32 = 0x00000004
	FILE_NO_INTERMEDIATE_BUFFERING uint32 = 0x00000008
	FILE_SYNCHRONOUS_IO_ALERT      uint32 = 0x00000010
	FILE_SYNCHRONOUS_IO_NONALERT   uint32 = 0x00000020
	FILE_NON_DIRECTORY_FILE        uint32 = 0x00000040
	FILE_COMPLETE_IF_OPLOCKED      uint32 = 0x00000100
	FILE_NO_EA_KNOWLEDGE           uint32 = 0x00000200
	FILE_RANDOM_ACCESS             uint32 = 0x00000800
	FILE_DELETE_ON_CLOSE           uint32 = 0x00001000
	FILE_OPEN_BY_FILE_ID           uint32 = 0x00002000
	FILE_OPEN_FOR_BACKUP_INTENT    uint32 = 0x00004000
	FILE_NO_COMPRESSION            uint32 = 0x00008000
	FILE_OPEN_REPARSE_POINT        uint32 = 0x00200000
	FILE_OPEN_NO_RECALL            uint32 = 0x00400000
)

SMB2 Create Options

View Source
const (
	FILE_SUPERSEDED  uint32 = 0x00000000
	FILE_OPENED      uint32 = 0x00000001
	FILE_CREATED     uint32 = 0x00000002
	FILE_OVERWRITTEN uint32 = 0x00000003
)

SMB2 Create Action (returned in CREATE response)

View Source
const (
	SMB2_NEGOTIATE_SIGNING_ENABLED  uint16 = 0x0001
	SMB2_NEGOTIATE_SIGNING_REQUIRED uint16 = 0x0002
)

SMB2 Security Mode

View Source
const (
	SMB2_GLOBAL_CAP_DFS                uint32 = 0x00000001
	SMB2_GLOBAL_CAP_LEASING            uint32 = 0x00000002
	SMB2_GLOBAL_CAP_LARGE_MTU          uint32 = 0x00000004
	SMB2_GLOBAL_CAP_MULTI_CHANNEL      uint32 = 0x00000008
	SMB2_GLOBAL_CAP_PERSISTENT_HANDLES uint32 = 0x00000010
	SMB2_GLOBAL_CAP_DIRECTORY_LEASING  uint32 = 0x00000020
	SMB2_GLOBAL_CAP_ENCRYPTION         uint32 = 0x00000040
)

SMB2 Capabilities

View Source
const (
	SMB2_SHARE_TYPE_DISK  uint8 = 0x01
	SMB2_SHARE_TYPE_PIPE  uint8 = 0x02
	SMB2_SHARE_TYPE_PRINT uint8 = 0x03
)

SMB2 Share Type

View Source
const (
	SMB2_SHAREFLAG_MANUAL_CACHING              uint32 = 0x00000000
	SMB2_SHAREFLAG_AUTO_CACHING                uint32 = 0x00000010
	SMB2_SHAREFLAG_VDO_CACHING                 uint32 = 0x00000020
	SMB2_SHAREFLAG_NO_CACHING                  uint32 = 0x00000030
	SMB2_SHAREFLAG_DFS                         uint32 = 0x00000001
	SMB2_SHAREFLAG_DFS_ROOT                    uint32 = 0x00000002
	SMB2_SHAREFLAG_RESTRICT_EXCLUSIVE_OPENS    uint32 = 0x00000100
	SMB2_SHAREFLAG_FORCE_SHARED_DELETE         uint32 = 0x00000200
	SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING     uint32 = 0x00000400
	SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM uint32 = 0x00000800
	SMB2_SHAREFLAG_FORCE_LEVELII_OPLOCK        uint32 = 0x00001000
	SMB2_SHAREFLAG_ENABLE_HASH_V1              uint32 = 0x00002000
	SMB2_SHAREFLAG_ENABLE_HASH_V2              uint32 = 0x00004000
	SMB2_SHAREFLAG_ENCRYPT_DATA                uint32 = 0x00008000
)

SMB2 Share Flags

View Source
const (
	SMB2_SHARE_CAP_DFS                     uint32 = 0x00000008
	SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY uint32 = 0x00000010
	SMB2_SHARE_CAP_SCALEOUT                uint32 = 0x00000020
	SMB2_SHARE_CAP_CLUSTER                 uint32 = 0x00000040
	SMB2_SHARE_CAP_ASYMMETRIC              uint32 = 0x00000080
)

SMB2 Share Capabilities

View Source
const (
	SMB2_0_INFO_FILE       uint8 = 0x01
	SMB2_0_INFO_FILESYSTEM uint8 = 0x02
	SMB2_0_INFO_SECURITY   uint8 = 0x03
	SMB2_0_INFO_QUOTA      uint8 = 0x04
)

SMB2 Info Type (for QUERY_INFO and SET_INFO)

View Source
const (
	FileDirectoryInformation           uint8 = 1
	FileFullDirectoryInformation       uint8 = 2
	FileBothDirectoryInformation       uint8 = 3
	FileBasicInformation               uint8 = 4
	FileStandardInformation            uint8 = 5
	FileInternalInformation            uint8 = 6
	FileEaInformation                  uint8 = 7
	FileAccessInformation              uint8 = 8
	FileNameInformation                uint8 = 9
	FileRenameInformation              uint8 = 10
	FileLinkInformation                uint8 = 11
	FileNamesInformation               uint8 = 12
	FileDispositionInformation         uint8 = 13
	FilePositionInformation            uint8 = 14
	FileFullEaInformation              uint8 = 15
	FileModeInformation                uint8 = 16
	FileAlignmentInformation           uint8 = 17
	FileAllInformation                 uint8 = 18
	FileAllocationInformation          uint8 = 19
	FileEndOfFileInformation           uint8 = 20
	FileAlternateNameInformation       uint8 = 21
	FileStreamInformation              uint8 = 22
	FilePipeInformation                uint8 = 23
	FilePipeLocalInformation           uint8 = 24
	FilePipeRemoteInformation          uint8 = 25
	FileMailslotQueryInformation       uint8 = 26
	FileMailslotSetInformation         uint8 = 27
	FileCompressionInformation         uint8 = 28
	FileObjectIdInformation            uint8 = 29
	FileMoveClusterInformation         uint8 = 31
	FileQuotaInformation               uint8 = 32
	FileReparsePointInformation        uint8 = 33
	FileNetworkOpenInformation         uint8 = 34
	FileAttributeTagInformation        uint8 = 35
	FileIdBothDirectoryInformation     uint8 = 37
	FileIdFullDirectoryInformation     uint8 = 38
	FileValidDataLengthInformation     uint8 = 39
	FileShortNameInformation           uint8 = 40
	FileIdGlobalTxDirectoryInformation uint8 = 50
)

File Information Classes

View Source
const (
	FileFsVolumeInformation     uint8 = 1
	FileFsLabelInformation      uint8 = 2
	FileFsSizeInformation       uint8 = 3
	FileFsDeviceInformation     uint8 = 4
	FileFsAttributeInformation  uint8 = 5
	FileFsControlInformation    uint8 = 6
	FileFsFullSizeInformation   uint8 = 7
	FileFsObjectIdInformation   uint8 = 8
	FileFsSectorSizeInformation uint8 = 11
)

Filesystem Information Classes

View Source
const (
	SMB2_PREAUTH_INTEGRITY_SHA512 uint16 = 0x0001
)

SMB 3.1.1 Hash Algorithms

View Source
const (
	SMB2_SESSION_FLAG_BINDING uint16 = 0x01 // Session binding (multi-channel)
)

SMB2 Session Setup flags

Variables

View Source
var (
	// ErrNotImplemented indicates a feature is not yet implemented.
	ErrNotImplemented = errors.New("not implemented")

	// ErrInvalidConfig indicates the configuration is invalid.
	ErrInvalidConfig = errors.New("invalid configuration")

	// ErrConnectionClosed indicates the connection has been closed.
	ErrConnectionClosed = errors.New("connection closed")

	// ErrPoolExhausted indicates all connections in the pool are in use.
	ErrPoolExhausted = errors.New("connection pool exhausted")

	// ErrAuthenticationFailed indicates authentication failed.
	ErrAuthenticationFailed = errors.New("authentication failed")

	// ErrUnsupportedDialect indicates the SMB dialect is not supported.
	ErrUnsupportedDialect = errors.New("unsupported SMB dialect")

	// ErrInvalidPath indicates the path is invalid.
	ErrInvalidPath = errors.New("invalid path")

	// ErrNotDirectory indicates the path is not a directory.
	ErrNotDirectory = errors.New("not a directory")

	// ErrIsDirectory indicates the path is a directory.
	ErrIsDirectory = errors.New("is a directory")
)
View Source
var (
	ErrInvalidMessage = errors.New("invalid SMB message")
	ErrServerClosed   = errors.New("server closed")
)

Errors specific to the server

View Source
var SupportedDialects = []SMBDialect{
	SMB3_1_1,
	SMB3_0_2,
	SMB3_0,
	SMB2_1,
	SMB2_0_2,
}

SupportedDialects lists dialects we support (highest to lowest preference)

Functions

func AlignTo8

func AlignTo8(v int) int

AlignTo8 aligns a value up to the next 8-byte boundary

func ApplySignature

func ApplySignature(message []byte, signature []byte)

ApplySignature applies a signature to an SMB2 message It modifies the message in place

func CommandName

func CommandName(cmd uint16) string

CommandName returns the human-readable name for an SMB2 command

func DecodeUTF16LEToString

func DecodeUTF16LEToString(data []byte) string

DecodeUTF16LEToString decodes UTF-16LE bytes to a Go string

func DeriveSigningKey

func DeriveSigningKey(sessionKey []byte, dialect SMBDialect, preauthHash []byte) []byte

DeriveSigningKey derives the signing key for SMB 3.x using SP800-108 KDF For SMB 3.0/3.0.2: SigningKey = KDF(SessionKey, "SMB2AESCMAC\0", "SmbSign\0") For SMB 3.1.1: SigningKey = KDF(SessionKey, "SMBSigningKey\0", PreauthIntegrityHash)

func EncodeStringToUTF16LE

func EncodeStringToUTF16LE(s string) []byte

EncodeStringToUTF16LE encodes a Go string to UTF-16LE bytes (SMB wire format)

func FiletimeToTime

func FiletimeToTime(ft uint64) time.Time

FiletimeToTime converts a Windows FILETIME to Go time.Time

func GUIDToString

func GUIDToString(guid [16]byte) string

GUIDToString converts a GUID to string format (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)

func InitPreauthHash

func InitPreauthHash() []byte

InitPreauthHash initializes the preauth integrity hash for SMB 3.1.1 Per MS-SMB2 3.2.5.2, the initial hash is 64 zero bytes

func IsMessageSigned

func IsMessageSigned(message []byte) bool

IsMessageSigned checks if an SMB2 message has the signed flag set

func IsValidCommand

func IsValidCommand(cmd uint16) bool

IsValidCommand returns true if the command is a valid SMB2 command

func NewGUID

func NewGUID() [16]byte

NewGUID creates a new random GUID

func PadTo8ByteBoundary

func PadTo8ByteBoundary(offset int) int

PadTo8ByteBoundary returns the number of padding bytes needed to align to 8-byte boundary

func SetSignedFlag

func SetSignedFlag(message []byte)

SetSignedFlag sets the SMB2_FLAGS_SIGNED flag in the message header

func SignMessage

func SignMessage(message []byte, signingKey []byte, dialect SMBDialect) []byte

SignMessage signs an SMB2 message using the appropriate algorithm for the dialect Returns the signature bytes (16 bytes) to be placed in the header

func TimeToFiletime

func TimeToFiletime(t time.Time) uint64

TimeToFiletime converts a Go time.Time to Windows FILETIME

func UpdatePreauthHash

func UpdatePreauthHash(currentHash []byte, message []byte) []byte

UpdatePreauthHash updates the preauth integrity hash with a message Per MS-SMB2 3.2.5.2:

PreauthIntegrityHashValue = SHA-512(PreviousHash || MessageBytes)

This is called after NEGOTIATE request/response and SESSION_SETUP request/response

func VerifySignature

func VerifySignature(message []byte, signingKey []byte, dialect SMBDialect) bool

VerifySignature verifies an SMB2 message signature

Types

type AuthResult

type AuthResult struct {
	Success    bool   // Whether authentication succeeded
	IsGuest    bool   // Whether this is a guest session
	Username   string // Authenticated username (empty for guest)
	Domain     string // User's domain (empty for guest)
	SessionKey []byte // Session signing key (nil for guest/unsigned)

	// For multi-stage auth (like NTLM), this contains the security blob to return
	// If nil and Success=false, authentication is complete but failed
	// If non-nil and Success=false, more processing is required (STATUS_MORE_PROCESSING_REQUIRED)
	ResponseBlob []byte
}

AuthResult contains the result of an authentication attempt

type Authenticator

type Authenticator interface {
	// Authenticate processes an authentication request and returns the result
	// securityBlob is the security buffer from the SESSION_SETUP request
	Authenticate(securityBlob []byte) (*AuthResult, error)
}

Authenticator represents an authentication mechanism for SMB sessions

type ByteReader

type ByteReader struct {
	// contains filtered or unexported fields
}

ByteReader provides convenient methods for reading binary data

func NewByteReader

func NewByteReader(data []byte) *ByteReader

NewByteReader creates a new ByteReader

func (*ByteReader) Position

func (r *ByteReader) Position() int

Position returns the current position

func (*ByteReader) ReadBytes

func (r *ByteReader) ReadBytes(n int) []byte

ReadBytes reads n bytes and advances position

func (*ByteReader) ReadFileID

func (r *ByteReader) ReadFileID() FileID

ReadFileID reads a 16-byte FileID

func (*ByteReader) ReadGUID

func (r *ByteReader) ReadGUID() [16]byte

ReadGUID reads a 16-byte GUID

func (*ByteReader) ReadOneByte

func (r *ByteReader) ReadOneByte() byte

ReadOneByte reads a single byte (named to avoid conflict with io.ByteReader)

func (*ByteReader) ReadUTF16String

func (r *ByteReader) ReadUTF16String(byteLen int) string

ReadUTF16String reads a UTF-16LE string of specified byte length

func (*ByteReader) ReadUint16

func (r *ByteReader) ReadUint16() uint16

ReadUint16 reads a little-endian uint16

func (*ByteReader) ReadUint32

func (r *ByteReader) ReadUint32() uint32

ReadUint32 reads a little-endian uint32

func (*ByteReader) ReadUint64

func (r *ByteReader) ReadUint64() uint64

ReadUint64 reads a little-endian uint64

func (*ByteReader) Remaining

func (r *ByteReader) Remaining() int

Remaining returns the number of unread bytes

func (*ByteReader) Seek

func (r *ByteReader) Seek(pos int)

Seek sets the position

func (*ByteReader) Skip

func (r *ByteReader) Skip(n int)

Skip advances the position by n bytes

type ByteWriter

type ByteWriter struct {
	// contains filtered or unexported fields
}

ByteWriter provides convenient methods for writing binary data

func NewByteWriter

func NewByteWriter(capacity int) *ByteWriter

NewByteWriter creates a new ByteWriter with initial capacity

func (*ByteWriter) Bytes

func (w *ByteWriter) Bytes() []byte

Bytes returns the written bytes

func (*ByteWriter) Len

func (w *ByteWriter) Len() int

Len returns the number of written bytes

func (*ByteWriter) Reset

func (w *ByteWriter) Reset()

Reset clears all written data

func (*ByteWriter) SetUint16At

func (w *ByteWriter) SetUint16At(pos int, v uint16)

SetUint16At writes a uint16 at a specific position (for backpatching)

func (*ByteWriter) SetUint32At

func (w *ByteWriter) SetUint32At(pos int, v uint32)

SetUint32At writes a uint32 at a specific position (for backpatching)

func (*ByteWriter) WriteBytes

func (w *ByteWriter) WriteBytes(b []byte)

WriteBytes appends raw bytes

func (*ByteWriter) WriteFileID

func (w *ByteWriter) WriteFileID(f FileID)

WriteFileID appends a 16-byte FileID

func (*ByteWriter) WriteGUID

func (w *ByteWriter) WriteGUID(guid [16]byte)

WriteGUID appends a 16-byte GUID

func (*ByteWriter) WriteOneByte

func (w *ByteWriter) WriteOneByte(b byte)

WriteOneByte appends a single byte (named to avoid conflict with io.ByteWriter)

func (*ByteWriter) WritePadTo8

func (w *ByteWriter) WritePadTo8()

WritePadTo8 pads to 8-byte boundary

func (*ByteWriter) WriteUTF16String

func (w *ByteWriter) WriteUTF16String(s string)

WriteUTF16String appends a UTF-16LE encoded string

func (*ByteWriter) WriteUint16

func (w *ByteWriter) WriteUint16(v uint16)

WriteUint16 appends a little-endian uint16

func (*ByteWriter) WriteUint32

func (w *ByteWriter) WriteUint32(v uint32)

WriteUint32 appends a little-endian uint32

func (*ByteWriter) WriteUint64

func (w *ByteWriter) WriteUint64(v uint64)

WriteUint64 appends a little-endian uint64

func (*ByteWriter) WriteZeros

func (w *ByteWriter) WriteZeros(n int)

WriteZeros appends n zero bytes

type CacheConfig

type CacheConfig struct {
	// EnableCache enables metadata caching. Default: false for safety.
	EnableCache bool

	// DirCacheTTL is the time-to-live for directory listings.
	// Default: 5 seconds. Set to 0 to disable directory caching.
	DirCacheTTL time.Duration

	// StatCacheTTL is the time-to-live for file stat results.
	// Default: 5 seconds. Set to 0 to disable stat caching.
	StatCacheTTL time.Duration

	// MaxCacheEntries is the maximum number of cache entries.
	// When exceeded, oldest entries are evicted. Default: 1000.
	MaxCacheEntries int
}

CacheConfig configures the metadata cache behavior.

func DefaultCacheConfig

func DefaultCacheConfig() CacheConfig

DefaultCacheConfig returns a cache configuration with reasonable defaults.

type CacheStats

type CacheStats struct {
	Enabled          bool
	DirCacheEntries  int
	StatCacheEntries int
	TotalEntries     int
	MaxEntries       int
}

CacheStats provides statistics about cache usage.

type CachingMode

type CachingMode uint32

CachingMode defines the client-side caching policy

const (
	CachingModeManual CachingMode = 0x00 // Manual caching (default)
	CachingModeAuto   CachingMode = 0x10 // Auto caching for documents
	CachingModeVDO    CachingMode = 0x20 // Auto caching for programs
	CachingModeNone   CachingMode = 0x30 // No caching
)

type Config

type Config struct {
	// Server connection
	Server string // Hostname or IP address
	Port   int    // SMB port (default: 445)
	Share  string // Share name

	// Authentication
	Username    string // Username (domain\user or user@domain)
	Password    string // Password
	Domain      string // Domain name (optional)
	UseKerberos bool   // Use Kerberos authentication
	GuestAccess bool   // Anonymous/guest access

	// SMB protocol
	Dialect    string // Preferred dialect (SMB2, SMB3, etc.)
	Signing    bool   // Require message signing
	Encryption bool   // Require encryption (SMB3+)

	// Connection pool
	MaxIdle     int           // Max idle connections (default: 5)
	MaxOpen     int           // Max open connections (default: 10)
	IdleTimeout time.Duration // Idle timeout (default: 5m)
	ConnTimeout time.Duration // Connection timeout (default: 30s)
	OpTimeout   time.Duration // Operation timeout (default: 60s)

	// Behavior
	CaseSensitive  bool // Case-sensitive paths (default: false)
	FollowSymlinks bool // Follow Windows symlinks/junctions

	// Performance
	ReadBufferSize  int         // Read buffer size (default: 64KB)
	WriteBufferSize int         // Write buffer size (default: 64KB)
	Cache           CacheConfig // Metadata caching configuration

	// Retry and reliability
	RetryPolicy *RetryPolicy // Retry policy for failed operations (nil = use default)

	// Logging
	Logger Logger // Logger for debug and error messages (nil = no logging)
}

Config holds the configuration for an SMB filesystem connection.

func ParseConnectionString

func ParseConnectionString(connStr string) (*Config, error)

ParseConnectionString parses an SMB connection string into a Config. Supported formats:

smb://[domain\]username:password@server[:port]/share[/path]
smb://server/share  // Guest access
smb://user:pass@server/share
smb://DOMAIN\user:pass@server/share
smb://server:10445/share  // Non-standard port

func (*Config) Validate

func (c *Config) Validate() error

Validate checks if the configuration is valid.

type ConnectionFactory

type ConnectionFactory interface {
	// CreateConnection creates a new SMB connection using the provided config.
	CreateConnection(config *Config) (SMBSession, SMBShare, error)
}

ConnectionFactory creates SMB connections for the connection pool. This abstraction allows injection of mock connections for testing.

type DefaultLogger

type DefaultLogger struct {
	// contains filtered or unexported fields
}

DefaultLogger wraps the standard log package

func NewDefaultLogger

func NewDefaultLogger(debug bool) *DefaultLogger

NewDefaultLogger creates a default logger

func (*DefaultLogger) Debug

func (l *DefaultLogger) Debug(msg string, args ...interface{})

func (*DefaultLogger) Error

func (l *DefaultLogger) Error(msg string, args ...interface{})

func (*DefaultLogger) Info

func (l *DefaultLogger) Info(msg string, args ...interface{})

func (*DefaultLogger) Warn

func (l *DefaultLogger) Warn(msg string, args ...interface{})

type File

type File struct {
	// contains filtered or unexported fields
}

File represents an open file on an SMB share.

func (*File) Close

func (f *File) Close() error

Close closes the file.

func (*File) Name

func (f *File) Name() string

Name returns the name of the file.

func (*File) Read

func (f *File) Read(p []byte) (n int, err error)

Read reads up to len(p) bytes into p.

func (*File) ReadAt

func (f *File) ReadAt(b []byte, off int64) (n int, err error)

ReadAt reads len(b) bytes from the File starting at byte offset off.

func (*File) ReadDir

func (f *File) ReadDir(n int) ([]fs.DirEntry, error)

ReadDir reads the contents of the directory.

func (*File) Readdir

func (f *File) Readdir(n int) ([]fs.FileInfo, error)

Readdir reads directory information.

func (*File) Readdirnames

func (f *File) Readdirnames(n int) ([]string, error)

Readdirnames reads directory names.

func (*File) Seek

func (f *File) Seek(offset int64, whence int) (int64, error)

Seek sets the offset for the next Read or Write on the file.

func (*File) Stat

func (f *File) Stat() (fs.FileInfo, error)

Stat returns file information.

func (*File) Sync

func (f *File) Sync() error

Sync commits the current contents of the file to stable storage.

func (*File) Truncate

func (f *File) Truncate(size int64) error

Truncate changes the size of the file.

func (*File) Write

func (f *File) Write(p []byte) (n int, err error)

Write writes len(p) bytes from p to the file.

func (*File) WriteAt

func (f *File) WriteAt(b []byte, off int64) (n int, err error)

WriteAt writes len(b) bytes to the File starting at byte offset off.

func (*File) WriteString

func (f *File) WriteString(s string) (n int, err error)

WriteString writes a string to the file.

type FileHandleMap

type FileHandleMap struct {
	// contains filtered or unexported fields
}

FileHandleMap manages SMB FileID to OpenFile mappings Thread-safe for concurrent access from multiple connections

func NewFileHandleMap

func NewFileHandleMap() *FileHandleMap

NewFileHandleMap creates a new file handle map

func (*FileHandleMap) Allocate

func (m *FileHandleMap) Allocate(file absfs.File, path string, isDir bool, access, shareAccess, disposition, options uint32, treeID uint32, sessionID uint64) *OpenFile

Allocate creates a new file handle for the given file

func (*FileHandleMap) CheckShareAccess

func (m *FileHandleMap) CheckShareAccess(path string, desiredAccess, shareAccess uint32) bool

CheckShareAccess verifies if a new open with the given access and share mode is compatible with existing opens on the same path

func (*FileHandleMap) Count

func (m *FileHandleMap) Count() int

Count returns the number of open handles

func (*FileHandleMap) Get

func (m *FileHandleMap) Get(id FileID) *OpenFile

Get retrieves an open file by its FileID

func (*FileHandleMap) GetBySession

func (m *FileHandleMap) GetBySession(id FileID, sessionID uint64) *OpenFile

GetBySession retrieves an open file, validating it belongs to the given session

func (*FileHandleMap) GetByTree

func (m *FileHandleMap) GetByTree(id FileID, treeID uint32, sessionID uint64) *OpenFile

GetByTree retrieves an open file, validating it belongs to the given tree

func (*FileHandleMap) GetDeleteOnClose

func (m *FileHandleMap) GetDeleteOnClose(id FileID) bool

GetDeleteOnClose returns whether a file should be deleted when closed

func (*FileHandleMap) GetOpenHandlesForPath

func (m *FileHandleMap) GetOpenHandlesForPath(path string) []*OpenFile

GetOpenHandlesForPath returns all open handles for a given path

func (*FileHandleMap) Release

func (m *FileHandleMap) Release(id FileID) error

Release closes and removes a file handle

func (*FileHandleMap) ReleaseBySession

func (m *FileHandleMap) ReleaseBySession(sessionID uint64) []error

ReleaseBySession releases all handles belonging to a session

func (*FileHandleMap) ReleaseByTree

func (m *FileHandleMap) ReleaseByTree(treeID uint32, sessionID uint64) []error

ReleaseByTree releases all handles belonging to a tree connection

func (*FileHandleMap) SetDeleteOnClose

func (m *FileHandleMap) SetDeleteOnClose(id FileID, deleteOnClose bool)

SetDeleteOnClose marks a file to be deleted when closed

func (*FileHandleMap) UpdateLastAccess

func (m *FileHandleMap) UpdateLastAccess(id FileID)

UpdateLastAccess updates the last access time for a handle

type FileID

type FileID struct {
	Persistent uint64
	Volatile   uint64
}

FileID is a 128-bit SMB2 file identifier

func UnmarshalFileID

func UnmarshalFileID(data []byte) FileID

UnmarshalFileID decodes a FileID from bytes

func (FileID) IsZero

func (f FileID) IsZero() bool

IsZero returns true if the FileID is zero/invalid

func (FileID) Marshal

func (f FileID) Marshal() []byte

Marshal encodes the FileID to bytes

type FileInfoEx

type FileInfoEx interface {
	fs.FileInfo
	// WindowsAttributes returns the Windows-specific file attributes.
	// Returns nil if attributes are not available.
	WindowsAttributes() *WindowsAttributes
}

FileInfoEx extends fs.FileInfo with Windows attributes.

type FileSystem

type FileSystem struct {
	// contains filtered or unexported fields
}

FileSystem implements absfs.FileSystem for SMB/CIFS network shares.

func New

func New(config *Config) (*FileSystem, error)

New creates a new SMB filesystem.

func NewWithFactory

func NewWithFactory(config *Config, factory ConnectionFactory) (*FileSystem, error)

NewWithFactory creates a new SMB filesystem with a custom connection factory. This is primarily used for testing with mock connections.

func (*FileSystem) Chdir

func (fsys *FileSystem) Chdir(dir string) error

Chdir changes the current working directory. For SMB filesystems, this is not typically used as paths are absolute.

func (*FileSystem) Chmod

func (fsys *FileSystem) Chmod(name string, mode fs.FileMode) error

Chmod changes the mode of a file.

func (*FileSystem) Chown

func (fsys *FileSystem) Chown(name string, uid, gid int) error

Chown changes the owner of a file.

func (*FileSystem) Chtimes

func (fsys *FileSystem) Chtimes(name string, atime, mtime time.Time) error

Chtimes changes the access and modification times of a file.

func (*FileSystem) Close

func (fsys *FileSystem) Close() error

Close closes the filesystem and releases all resources.

func (*FileSystem) Create

func (fsys *FileSystem) Create(name string) (absfs.File, error)

Create creates a new file for writing.

func (*FileSystem) Getwd

func (fsys *FileSystem) Getwd() (string, error)

Getwd returns the current working directory. For SMB filesystems, this always returns "/" as there's no real working directory concept.

func (*FileSystem) ListShares

func (fsys *FileSystem) ListShares(ctx context.Context) ([]ShareInfo, error)

ListShares returns a list of available shares on the SMB server.

This method connects to the IPC$ share to enumerate available shares. The connection uses the same credentials as the main filesystem.

Note: Some servers may restrict share enumeration. If the operation fails, it may be due to insufficient permissions or server configuration.

Example:

shares, err := fsys.ListShares(ctx)
if err != nil {
    return err
}
for _, share := range shares {
    fmt.Printf("%s: %s (%s)\n", share.Name, share.Comment, share.Type)
}

func (*FileSystem) Lstat

func (fsys *FileSystem) Lstat(name string) (fs.FileInfo, error)

Lstat returns file information (same as Stat for SMB).

func (*FileSystem) Mkdir

func (fsys *FileSystem) Mkdir(name string, perm fs.FileMode) error

Mkdir creates a directory.

func (*FileSystem) MkdirAll

func (fsys *FileSystem) MkdirAll(name string, perm fs.FileMode) error

MkdirAll creates a directory and all parent directories.

func (*FileSystem) Open

func (fsys *FileSystem) Open(name string) (absfs.File, error)

Open opens a file for reading.

func (*FileSystem) OpenFile

func (fsys *FileSystem) OpenFile(name string, flag int, perm fs.FileMode) (absfs.File, error)

OpenFile opens a file with the specified flags and mode.

func (*FileSystem) ReadDir

func (fsys *FileSystem) ReadDir(name string) ([]fs.DirEntry, error)

ReadDir reads the directory and returns directory entries.

func (*FileSystem) ReadFile

func (fsys *FileSystem) ReadFile(name string) ([]byte, error)

ReadFile reads the named file and returns its contents.

func (*FileSystem) Remove

func (fsys *FileSystem) Remove(name string) error

Remove removes a file or empty directory.

func (*FileSystem) RemoveAll

func (fsys *FileSystem) RemoveAll(name string) error

RemoveAll removes a path and all children.

func (*FileSystem) Rename

func (fsys *FileSystem) Rename(oldname, newname string) error

Rename renames (moves) a file or directory.

func (*FileSystem) Stat

func (fsys *FileSystem) Stat(name string) (fs.FileInfo, error)

Stat returns file information.

func (*FileSystem) Sub

func (fsys *FileSystem) Sub(dir string) (fs.FS, error)

Sub returns an fs.FS corresponding to the subtree rooted at dir.

func (*FileSystem) TempDir

func (fsys *FileSystem) TempDir() string

TempDir returns the default directory for temporary files. For SMB filesystems, this returns "/tmp" which can be created on the share.

func (*FileSystem) Truncate

func (fsys *FileSystem) Truncate(name string, size int64) error

Truncate changes the size of the named file.

type GuestAuthenticator

type GuestAuthenticator struct{}

GuestAuthenticator implements guest-only authentication This is a simple authenticator that always succeeds with guest access

func NewGuestAuthenticator

func NewGuestAuthenticator() *GuestAuthenticator

NewGuestAuthenticator creates a new guest authenticator

func (*GuestAuthenticator) Authenticate

func (a *GuestAuthenticator) Authenticate(securityBlob []byte) (*AuthResult, error)

Authenticate always succeeds with guest access In a real implementation, this would check if guest access is allowed

type Logger

type Logger interface {
	Printf(format string, v ...interface{})
}

Logger interface for logging operations.

type MockConnectionFactory

type MockConnectionFactory struct {
	Backend *MockSMBBackend

	// Error to return on CreateConnection
	ConnectError error
	// contains filtered or unexported fields
}

MockConnectionFactory implements ConnectionFactory for testing.

func NewMockConnectionFactory

func NewMockConnectionFactory(backend *MockSMBBackend) *MockConnectionFactory

NewMockConnectionFactory creates a new mock connection factory.

func (*MockConnectionFactory) ConnectAttempts

func (f *MockConnectionFactory) ConnectAttempts() int

ConnectAttempts returns the total connection attempts.

func (*MockConnectionFactory) ConnectionsMade

func (f *MockConnectionFactory) ConnectionsMade() int

ConnectionsMade returns the number of successful connections.

func (*MockConnectionFactory) CreateConnection

func (f *MockConnectionFactory) CreateConnection(config *Config) (SMBSession, SMBShare, error)

CreateConnection creates a mock SMB connection.

func (*MockConnectionFactory) Reset

func (f *MockConnectionFactory) Reset()

Reset resets the connection tracking.

type MockOperation

type MockOperation struct {
	Op   string
	Path string
	Args []interface{}
	Time time.Time
}

MockOperation records an operation performed on the mock backend.

type MockSMBBackend

type MockSMBBackend struct {
	// contains filtered or unexported fields
}

MockSMBBackend provides an in-memory SMB server simulation for testing. It maintains a virtual filesystem that can be populated with test data and tracks all operations for verification.

func NewMockSMBBackend

func NewMockSMBBackend() *MockSMBBackend

NewMockSMBBackend creates a new mock SMB backend with default shares.

func (*MockSMBBackend) AddDir

func (m *MockSMBBackend) AddDir(path string, mode fs.FileMode)

AddDir adds a directory to the mock filesystem.

func (*MockSMBBackend) AddFile

func (m *MockSMBBackend) AddFile(path string, content []byte, mode fs.FileMode)

AddFile adds a file to the mock filesystem.

func (*MockSMBBackend) AddShare

func (m *MockSMBBackend) AddShare(name string)

AddShare adds a share to the mock backend. Note: This method acquires the lock internally.

func (*MockSMBBackend) ClearErrors

func (m *MockSMBBackend) ClearErrors()

ClearErrors clears all injected errors.

func (*MockSMBBackend) ClearOperations

func (m *MockSMBBackend) ClearOperations()

ClearOperations clears the operation history.

func (*MockSMBBackend) FileExists

func (m *MockSMBBackend) FileExists(path string) bool

FileExists returns true if the file exists.

func (*MockSMBBackend) GetFile

func (m *MockSMBBackend) GetFile(path string) ([]byte, bool)

GetFile returns the content of a file (for test verification).

func (*MockSMBBackend) GetOperations

func (m *MockSMBBackend) GetOperations() []MockOperation

GetOperations returns all recorded operations.

func (*MockSMBBackend) SetError

func (m *MockSMBBackend) SetError(path string, err error)

SetError sets an error to return for a specific path.

func (*MockSMBBackend) SetOperationError

func (m *MockSMBBackend) SetOperationError(op string, err error)

SetOperationError sets an error to return for a specific operation type.

type MockSMBFile

type MockSMBFile struct {
	// contains filtered or unexported fields
}

MockSMBFile implements SMBFile for testing.

func (*MockSMBFile) Close

func (f *MockSMBFile) Close() error

Close closes the file.

func (*MockSMBFile) Read

func (f *MockSMBFile) Read(p []byte) (n int, err error)

Read reads up to len(p) bytes into p.

func (*MockSMBFile) Readdir

func (f *MockSMBFile) Readdir(n int) ([]fs.FileInfo, error)

Readdir reads the directory contents.

func (*MockSMBFile) Seek

func (f *MockSMBFile) Seek(offset int64, whence int) (int64, error)

Seek sets the offset for the next Read or Write.

func (*MockSMBFile) Stat

func (f *MockSMBFile) Stat() (fs.FileInfo, error)

Stat returns file information.

func (*MockSMBFile) Write

func (f *MockSMBFile) Write(p []byte) (n int, err error)

Write writes len(p) bytes from p to the file.

type MockSMBSession

type MockSMBSession struct {
	// contains filtered or unexported fields
}

MockSMBSession implements SMBSession for testing.

func NewMockSMBSession

func NewMockSMBSession(backend *MockSMBBackend) *MockSMBSession

NewMockSMBSession creates a new mock SMB session.

func (*MockSMBSession) Logoff

func (s *MockSMBSession) Logoff() error

Logoff ends the session.

func (*MockSMBSession) Mount

func (s *MockSMBSession) Mount(shareName string) (SMBShare, error)

Mount mounts a share and returns an SMBShare interface.

type MockSMBShare

type MockSMBShare struct {
	// contains filtered or unexported fields
}

MockSMBShare implements SMBShare for testing.

func (*MockSMBShare) Chmod

func (sh *MockSMBShare) Chmod(name string, mode fs.FileMode) error

Chmod changes the mode of a file.

func (*MockSMBShare) Chtimes

func (sh *MockSMBShare) Chtimes(name string, atime, mtime time.Time) error

Chtimes changes the access and modification times of a file.

func (*MockSMBShare) Mkdir

func (sh *MockSMBShare) Mkdir(name string, perm fs.FileMode) error

Mkdir creates a directory.

func (*MockSMBShare) OpenFile

func (sh *MockSMBShare) OpenFile(name string, flag int, perm fs.FileMode) (SMBFile, error)

OpenFile opens a file with the specified flags and permissions.

func (*MockSMBShare) Remove

func (sh *MockSMBShare) Remove(name string) error

Remove removes a file or empty directory.

func (*MockSMBShare) Rename

func (sh *MockSMBShare) Rename(oldname, newname string) error

Rename renames a file or directory.

func (*MockSMBShare) Stat

func (sh *MockSMBShare) Stat(name string) (fs.FileInfo, error)

Stat returns file info for the specified path.

func (*MockSMBShare) Umount

func (sh *MockSMBShare) Umount() error

Umount unmounts the share.

type NTLMAuthenticator

type NTLMAuthenticator struct {
	// contains filtered or unexported fields
}

NTLMAuthenticator implements NTLM authentication for SMB

func NewNTLMAuthenticator

func NewNTLMAuthenticator(targetName string, users map[string]string, allowGuest bool) *NTLMAuthenticator

NewNTLMAuthenticator creates a new NTLM authenticator users is a map of username -> password (usernames are case-insensitive) If users is nil or empty and allowGuest is true, all connections are allowed as guest

func (*NTLMAuthenticator) Authenticate

func (a *NTLMAuthenticator) Authenticate(securityBlob []byte) (*AuthResult, error)

Authenticate processes NTLM authentication messages

type NTStatus

type NTStatus uint32

NT Status codes

const (
	STATUS_SUCCESS                  NTStatus = 0x00000000
	STATUS_PENDING                  NTStatus = 0x00000103
	STATUS_BUFFER_OVERFLOW          NTStatus = 0x80000005
	STATUS_NO_MORE_FILES            NTStatus = 0x80000006
	STATUS_INVALID_PARAMETER        NTStatus = 0xC000000D
	STATUS_NO_SUCH_FILE             NTStatus = 0xC000000F
	STATUS_END_OF_FILE              NTStatus = 0xC0000011
	STATUS_MORE_PROCESSING_REQUIRED NTStatus = 0xC0000016
	STATUS_ACCESS_DENIED            NTStatus = 0xC0000022
	STATUS_OBJECT_NAME_INVALID      NTStatus = 0xC0000033
	STATUS_OBJECT_NAME_NOT_FOUND    NTStatus = 0xC0000034
	STATUS_OBJECT_NAME_COLLISION    NTStatus = 0xC0000035
	STATUS_OBJECT_PATH_NOT_FOUND    NTStatus = 0xC000003A
	STATUS_SHARING_VIOLATION        NTStatus = 0xC0000043
	STATUS_DELETE_PENDING           NTStatus = 0xC0000056
	STATUS_PRIVILEGE_NOT_HELD       NTStatus = 0xC0000061
	STATUS_LOGON_FAILURE            NTStatus = 0xC000006D
	STATUS_ACCOUNT_RESTRICTION      NTStatus = 0xC000006E
	STATUS_PASSWORD_EXPIRED         NTStatus = 0xC0000071
	STATUS_INSUFFICIENT_RESOURCES   NTStatus = 0xC000009A
	STATUS_FILE_IS_A_DIRECTORY      NTStatus = 0xC00000BA
	STATUS_BAD_NETWORK_NAME         NTStatus = 0xC00000CC
	STATUS_NOT_SAME_DEVICE          NTStatus = 0xC00000D4
	STATUS_FILE_RENAMED             NTStatus = 0xC00000D5
	STATUS_NOT_A_DIRECTORY          NTStatus = 0xC0000103
	STATUS_FILE_CLOSED              NTStatus = 0xC0000128
	STATUS_CANCELLED                NTStatus = 0xC0000120
	STATUS_NETWORK_NAME_DELETED     NTStatus = 0xC00000C9
	STATUS_USER_SESSION_DELETED     NTStatus = 0xC0000203
	STATUS_NOT_FOUND                NTStatus = 0xC0000225
	STATUS_INVALID_DEVICE_REQUEST   NTStatus = 0xC0000010
	STATUS_DIRECTORY_NOT_EMPTY      NTStatus = 0xC0000101
	STATUS_NOT_SUPPORTED            NTStatus = 0xC00000BB
)

func (NTStatus) IsError

func (s NTStatus) IsError() bool

IsError returns true if status indicates an error (high bit set)

func (NTStatus) IsSuccess

func (s NTStatus) IsSuccess() bool

IsSuccess returns true if status indicates success

func (NTStatus) String

func (s NTStatus) String() string

String returns the status name

type NullLogger

type NullLogger struct{}

NullLogger discards all log messages

func (*NullLogger) Debug

func (l *NullLogger) Debug(msg string, args ...interface{})

func (*NullLogger) Error

func (l *NullLogger) Error(msg string, args ...interface{})

func (*NullLogger) Info

func (l *NullLogger) Info(msg string, args ...interface{})

func (*NullLogger) Warn

func (l *NullLogger) Warn(msg string, args ...interface{})

type OpenFile

type OpenFile struct {
	ID            FileID     // SMB2 file identifier
	File          absfs.File // The underlying absfs file
	Path          string     // Path to the file (for debugging/logging)
	IsDir         bool       // True if this is a directory
	Access        uint32     // Access mask (read, write, etc.)
	ShareAccess   uint32     // Share access flags
	Disposition   uint32     // Create disposition used
	Options       uint32     // Create options used
	CreatedAt     time.Time  // When the handle was created
	LastAccess    time.Time  // Last access time
	TreeID        uint32     // Tree ID this handle belongs to
	SessionID     uint64     // Session ID this handle belongs to
	DeleteOnClose bool       // Delete file when handle is closed
}

OpenFile represents an open file handle in the SMB server

type PoolStats

type PoolStats struct {
	TotalConnections  int
	ActiveConnections int
	IdleConnections   int
	WaitersCount      int
	IsClosed          bool
}

Stats returns pool statistics for monitoring.

type RealConnectionFactory

type RealConnectionFactory struct{}

RealConnectionFactory implements ConnectionFactory using real SMB connections.

func (*RealConnectionFactory) CreateConnection

func (f *RealConnectionFactory) CreateConnection(config *Config) (SMBSession, SMBShare, error)

CreateConnection creates a real SMB connection.

type RetryPolicy

type RetryPolicy struct {
	MaxAttempts  int           // Maximum number of attempts (default: 3)
	InitialDelay time.Duration // Initial delay between retries (default: 100ms)
	MaxDelay     time.Duration // Maximum delay between retries (default: 5s)
	Multiplier   float64       // Backoff multiplier (default: 2.0)
}

RetryPolicy defines retry behavior for operations.

type SMB2Header

type SMB2Header struct {
	ProtocolID    [4]byte  // 0xFE 'S' 'M' 'B'
	StructureSize uint16   // Always 64
	CreditCharge  uint16   // Number of credits consumed
	Status        NTStatus // NT status code (response) or channel sequence (request)
	Command       uint16   // SMB2 command code
	CreditRequest uint16   // Credits requested (request) or granted (response)
	Flags         uint32   // Flags
	NextCommand   uint32   // Offset to next command in compound
	MessageID     uint64   // Unique message identifier
	Reserved      uint32   // Reserved (or AsyncID high bits)
	TreeID        uint32   // Tree identifier
	SessionID     uint64   // Session identifier
	Signature     [16]byte // Message signature (if signed)
}

SMB2Header represents the fixed 64-byte header for all SMB2/3 messages

func UnmarshalSMB2Header

func UnmarshalSMB2Header(data []byte) (*SMB2Header, error)

UnmarshalSMB2Header decodes an SMB2 header from bytes

func (*SMB2Header) IsResponse

func (h *SMB2Header) IsResponse() bool

IsResponse returns true if this is a response message

func (*SMB2Header) IsSigned

func (h *SMB2Header) IsSigned() bool

IsSigned returns true if the message is signed

func (*SMB2Header) Marshal

func (h *SMB2Header) Marshal() []byte

Marshal encodes the header to bytes

type SMB2Message

type SMB2Message struct {
	Header  *SMB2Header
	Payload []byte

	// Raw message bytes (for preauth hash computation)
	RawBytes []byte

	// Signing information (set when message should be signed)
	SigningKey []byte     // Key to use for signing
	Dialect    SMBDialect // Dialect for signing algorithm selection
}

SMB2Message wraps a header and payload

type SMBDialect

type SMBDialect uint16

SMB2 Dialects

const (
	SMB2_0_2 SMBDialect = 0x0202 // Windows Vista/Server 2008
	SMB2_1   SMBDialect = 0x0210 // Windows 7/Server 2008 R2
	SMB3_0   SMBDialect = 0x0300 // Windows 8/Server 2012
	SMB3_0_2 SMBDialect = 0x0302 // Windows 8.1/Server 2012 R2
	SMB3_1_1 SMBDialect = 0x0311 // Windows 10/Server 2016+
)

func (SMBDialect) String

func (d SMBDialect) String() string

String returns the dialect name

type SMBDialer

type SMBDialer interface {
	// Dial establishes an SMB session over the given connection.
	// The conn parameter should be a net.Conn.
	Dial(conn interface{}) (SMBSession, error)
}

SMBDialer abstracts the SMB connection dialer for testability. This allows injection of mock dialers for testing.

type SMBFile

type SMBFile interface {
	// Read reads up to len(p) bytes into p.
	Read(p []byte) (n int, err error)
	// Write writes len(p) bytes from p to the file.
	Write(p []byte) (n int, err error)
	// Seek sets the offset for the next Read or Write.
	Seek(offset int64, whence int) (int64, error)
	// Close closes the file.
	Close() error
	// Stat returns file information.
	Stat() (fs.FileInfo, error)
	// Readdir reads the directory contents.
	Readdir(n int) ([]fs.FileInfo, error)
}

SMBFile abstracts an SMB file handle for testability. This interface wraps the go-smb2 File type.

type SMBHandler

type SMBHandler struct {
	// contains filtered or unexported fields
}

SMBHandler routes SMB2/3 messages to appropriate handlers

func NewSMBHandler

func NewSMBHandler(server *Server) *SMBHandler

NewSMBHandler creates a new SMB handler

func (*SMBHandler) HandleMessage

func (h *SMBHandler) HandleMessage(state *connState, msg *SMB2Message) (*SMB2Message, error)

HandleMessage routes an incoming message to the appropriate handler

type SMBSession

type SMBSession interface {
	// Mount mounts a share and returns an SMBShare interface.
	Mount(shareName string) (SMBShare, error)
	// Logoff ends the session.
	Logoff() error
}

SMBSession abstracts an SMB session for testability. This interface wraps the go-smb2 Session type.

type SMBShare

type SMBShare interface {
	// OpenFile opens a file with the specified flags and permissions.
	OpenFile(name string, flag int, perm fs.FileMode) (SMBFile, error)
	// Stat returns file info for the specified path.
	Stat(name string) (fs.FileInfo, error)
	// Mkdir creates a directory.
	Mkdir(name string, perm fs.FileMode) error
	// Remove removes a file or empty directory.
	Remove(name string) error
	// Rename renames a file or directory.
	Rename(oldname, newname string) error
	// Chmod changes the mode of a file.
	Chmod(name string, mode fs.FileMode) error
	// Chtimes changes the access and modification times of a file.
	Chtimes(name string, atime, mtime time.Time) error
	// Umount unmounts the share.
	Umount() error
}

SMBShare abstracts an SMB share for testability. This interface wraps the go-smb2 Share type.

type SMBShareType

type SMBShareType uint8

SMBShareType represents the type of SMB share (different from ShareType in shares.go)

const (
	SMBShareTypeDisk  SMBShareType = 0x01 // Standard disk share
	SMBShareTypePipe  SMBShareType = 0x02 // Named pipe share (IPC$)
	SMBShareTypePrint SMBShareType = 0x03 // Printer share
)

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server represents an SMB server instance

func NewServer

func NewServer(options ServerOptions) (*Server, error)

NewServer creates a new SMB server

func (*Server) AddShare

func (s *Server) AddShare(fs absfs.FileSystem, options ShareOptions) error

AddShare registers a new share backed by an absfs.FileSystem

func (*Server) Addr

func (s *Server) Addr() net.Addr

Addr returns the server's listening address

func (*Server) ConnectionCount

func (s *Server) ConnectionCount() int

ConnectionCount returns the current number of connections

func (*Server) GetShare

func (s *Server) GetShare(shareName string) *Share

GetShare retrieves a share by name

func (*Server) ListShares

func (s *Server) ListShares() []string

ListShares returns the names of all shares

func (*Server) Listen

func (s *Server) Listen() error

Listen starts the server and begins accepting connections

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

ListenAndServe starts the server and blocks until shutdown

func (*Server) Logger

func (s *Server) Logger() ServerLogger

Logger returns the server logger

func (*Server) Options

func (s *Server) Options() ServerOptions

Options returns the server options

func (*Server) RemoveShare

func (s *Server) RemoveShare(shareName string) error

RemoveShare removes a share

func (*Server) SessionCount

func (s *Server) SessionCount() int

SessionCount returns the number of active sessions

func (*Server) Sessions

func (s *Server) Sessions() *SessionManager

Sessions returns the session manager

func (*Server) Stop

func (s *Server) Stop() error

Stop gracefully shuts down the server

type ServerLogger

type ServerLogger interface {
	Debug(msg string, args ...interface{})
	Info(msg string, args ...interface{})
	Warn(msg string, args ...interface{})
	Error(msg string, args ...interface{})
}

ServerLogger defines the logging interface for the SMB server

type ServerOptions

type ServerOptions struct {
	// Network settings
	Port     int    // Listen port (default: 445)
	Hostname string // Bind hostname (default: "0.0.0.0")

	// Protocol settings
	MinDialect      SMBDialect // Minimum SMB dialect to accept (default: SMB2_0_2)
	MaxDialect      SMBDialect // Maximum SMB dialect to offer (default: SMB3_1_1)
	SigningRequired bool       // Require message signing (default: false)

	// Connection settings
	MaxConnections int           // Maximum concurrent connections (0 = unlimited)
	IdleTimeout    time.Duration // Connection idle timeout (default: 15m)
	ReadTimeout    time.Duration // Read timeout per message (default: 30s)
	WriteTimeout   time.Duration // Write timeout per message (default: 30s)

	// Server identity
	ServerGUID [16]byte // Server GUID (generated if zero)
	ServerName string   // NetBIOS name (optional)

	// Authentication
	Users      map[string]string // Server-level users: username -> password
	AllowGuest bool              // Allow guest/anonymous access (default: true)

	// Logging
	Logger ServerLogger // Logger interface (optional)
	Debug  bool         // Enable debug logging

	// Performance
	MaxReadSize  uint32 // Maximum read size (default: 8MB)
	MaxWriteSize uint32 // Maximum write size (default: 8MB)
}

ServerOptions defines server-level configuration

func DefaultServerOptions

func DefaultServerOptions() ServerOptions

DefaultServerOptions returns sensible default server options

type Session

type Session struct {
	ID           uint64
	State        SessionState
	Dialect      SMBDialect
	IsGuest      bool
	Username     string
	Domain       string
	SigningKey   []byte
	CreatedAt    time.Time
	LastActivity time.Time

	// Connection info
	ClientGUID [16]byte
	ClientIP   string

	// Authentication state (for multi-step auth like NTLM)
	Authenticator Authenticator
	// contains filtered or unexported fields
}

Session represents an authenticated SMB session

func (*Session) AddTreeConnection

func (s *Session) AddTreeConnection(shareName string, share *Share, readOnly bool) *TreeConnection

AddTreeConnection adds a tree connection to the session

func (*Session) GetAllTreeConnections

func (s *Session) GetAllTreeConnections() []*TreeConnection

GetAllTreeConnections returns all tree connections (for cleanup)

func (*Session) GetTreeConnection

func (s *Session) GetTreeConnection(id uint32) *TreeConnection

GetTreeConnection retrieves a tree connection by ID

func (*Session) RemoveTreeConnection

func (s *Session) RemoveTreeConnection(id uint32) *TreeConnection

RemoveTreeConnection removes a tree connection from the session

func (*Session) SetValid

func (s *Session) SetValid(username, domain string, isGuest bool, signingKey []byte)

SetValid marks the session as fully authenticated

func (*Session) TreeCount

func (s *Session) TreeCount() int

TreeCount returns the number of tree connections in this session

func (*Session) ValidateTreeConnection

func (s *Session) ValidateTreeConnection(id uint32) (*TreeConnection, NTStatus)

ValidateTreeConnection checks if a tree connection exists and is valid

type SessionManager

type SessionManager struct {
	// contains filtered or unexported fields
}

SessionManager tracks active sessions

func NewSessionManager

func NewSessionManager(idleLimit time.Duration) *SessionManager

NewSessionManager creates a new session manager

func (*SessionManager) CleanupExpired

func (m *SessionManager) CleanupExpired() []*Session

CleanupExpired removes expired/idle sessions

func (*SessionManager) CreateSession

func (m *SessionManager) CreateSession(dialect SMBDialect, clientGUID [16]byte, clientIP string) *Session

CreateSession creates a new session in InProgress state

func (*SessionManager) DestroySession

func (m *SessionManager) DestroySession(id uint64) *Session

DestroySession removes a session and all its tree connections

func (*SessionManager) GetSession

func (m *SessionManager) GetSession(id uint64) *Session

GetSession retrieves a session by ID

func (*SessionManager) GetSessionByGUID

func (m *SessionManager) GetSessionByGUID(guid [16]byte) *Session

GetSessionByGUID retrieves a session by client GUID (for reconnection)

func (*SessionManager) SessionCount

func (m *SessionManager) SessionCount() int

SessionCount returns the number of active sessions

func (*SessionManager) UpdateActivity

func (m *SessionManager) UpdateActivity(id uint64)

UpdateActivity updates the last activity time for a session

func (*SessionManager) ValidateSession

func (m *SessionManager) ValidateSession(id uint64) (*Session, NTStatus)

ValidateSession checks if a session exists and is valid

type SessionState

type SessionState int

SessionState represents the state of an SMB session

const (
	SessionStateInProgress SessionState = iota // SESSION_SETUP in progress
	SessionStateValid                          // Session is fully authenticated
	SessionStateExpired                        // Session has expired
)

type Share

type Share struct {
	// contains filtered or unexported fields
}

Share represents an SMB share backed by an absfs.FileSystem

func NewShare

func NewShare(fs absfs.FileSystem, options ShareOptions) *Share

NewShare creates a new share

func (*Share) AllowsGuest

func (s *Share) AllowsGuest() bool

AllowsGuest returns true if guest access is allowed

func (*Share) CheckUserAccess

func (s *Share) CheckUserAccess(username string, isGuest bool) bool

CheckUserAccess verifies if a user is allowed to access this share

func (*Share) FileHandles

func (s *Share) FileHandles() *FileHandleMap

FileHandles returns the file handle map for this share

func (*Share) FileSystem

func (s *Share) FileSystem() absfs.FileSystem

FileSystem returns the underlying filesystem

func (*Share) GetShareType

func (s *Share) GetShareType() SMBShareType

GetShareType returns the SMB share type (disk, pipe, print)

func (*Share) IsReadOnly

func (s *Share) IsReadOnly() bool

IsReadOnly returns true if the share is read-only

func (*Share) Options

func (s *Share) Options() ShareOptions

Options returns the share options

func (*Share) ValidateCredentials

func (s *Share) ValidateCredentials(username, password string) bool

ValidateCredentials checks username/password against configured users

type ShareInfo

type ShareInfo struct {
	Name    string    // Share name
	Type    ShareType // Share type
	Comment string    // Share description/comment
}

ShareInfo contains information about an SMB share.

type ShareOptions

type ShareOptions struct {
	// Share identity
	ShareName string       // Share name (e.g., "data") - required
	SharePath string       // Root path within the filesystem (default: "/")
	ShareType SMBShareType // Type of share (disk, pipe, etc.) - default: disk

	// Access control
	ReadOnly     bool              // Export as read-only
	AllowGuest   bool              // Allow anonymous/guest access
	AllowedUsers []string          // List of allowed usernames (nil = all authenticated users)
	AllowedIPs   []string          // List of allowed client IPs/subnets (nil = all)
	Users        map[string]string // username -> password for basic authentication

	// Share properties
	Comment  string // Share comment/description
	MaxUsers int    // Maximum concurrent users (0 = unlimited)
	Hidden   bool   // Hide from share enumeration

	// Cache settings
	CachingMode CachingMode // Client-side caching mode
}

ShareOptions defines the configuration for an SMB share export

func DefaultShareOptions

func DefaultShareOptions(shareName string) ShareOptions

DefaultShareOptions returns sensible default share options

type ShareType

type ShareType uint32

ShareType represents the type of SMB share.

const (
	// ShareTypeDisk represents a disk share (standard file share).
	ShareTypeDisk ShareType = 0x00000000

	// ShareTypePrintQueue represents a print queue share.
	ShareTypePrintQueue ShareType = 0x00000001

	// ShareTypeDevice represents a communication device share.
	ShareTypeDevice ShareType = 0x00000002

	// ShareTypeIPC represents an IPC share (named pipes).
	ShareTypeIPC ShareType = 0x00000003

	// ShareTypeSpecial represents special shares (admin shares: C$, IPC$, etc.).
	ShareTypeSpecial ShareType = 0x80000000

	// ShareTypeTemporary represents a temporary share.
	ShareTypeTemporary ShareType = 0x40000000
)

func (ShareType) String

func (st ShareType) String() string

String returns a human-readable string for the share type.

type TreeConnection

type TreeConnection struct {
	ID         uint32
	ShareName  string
	Share      *Share
	Session    *Session
	CreatedAt  time.Time
	IsReadOnly bool // Effective read-only status (share or session)
}

TreeConnection represents a connection to a share within a session

type WindowsAttributes

type WindowsAttributes struct {
	// contains filtered or unexported fields
}

WindowsAttributes represents Windows-specific file attributes.

func GetWindowsAttributes

func GetWindowsAttributes(info fs.FileInfo) *WindowsAttributes

GetWindowsAttributes attempts to extract Windows attributes from fs.FileInfo. Returns nil if the FileInfo doesn't support Windows attributes.

func NewWindowsAttributes

func NewWindowsAttributes(attrs uint32) *WindowsAttributes

NewWindowsAttributes creates a new WindowsAttributes from a uint32 value.

func (*WindowsAttributes) Attributes

func (wa *WindowsAttributes) Attributes() uint32

Attributes returns the raw attribute value.

func (*WindowsAttributes) IsArchive

func (wa *WindowsAttributes) IsArchive() bool

IsArchive returns true if the file has the archive attribute.

func (*WindowsAttributes) IsCompressed

func (wa *WindowsAttributes) IsCompressed() bool

IsCompressed returns true if the file is compressed.

func (*WindowsAttributes) IsEncrypted

func (wa *WindowsAttributes) IsEncrypted() bool

IsEncrypted returns true if the file is encrypted.

func (*WindowsAttributes) IsHidden

func (wa *WindowsAttributes) IsHidden() bool

IsHidden returns true if the file has the hidden attribute.

func (*WindowsAttributes) IsOffline

func (wa *WindowsAttributes) IsOffline() bool

IsOffline returns true if the file data is offline.

func (*WindowsAttributes) IsReadOnly

func (wa *WindowsAttributes) IsReadOnly() bool

IsReadOnly returns true if the file has the read-only attribute.

func (*WindowsAttributes) IsReparsePoint

func (wa *WindowsAttributes) IsReparsePoint() bool

IsReparsePoint returns true if the file is a reparse point (symlink/junction).

func (*WindowsAttributes) IsSparse

func (wa *WindowsAttributes) IsSparse() bool

IsSparse returns true if the file is a sparse file.

func (*WindowsAttributes) IsSystem

func (wa *WindowsAttributes) IsSystem() bool

IsSystem returns true if the file has the system attribute.

func (*WindowsAttributes) IsTemporary

func (wa *WindowsAttributes) IsTemporary() bool

IsTemporary returns true if the file has the temporary attribute.

func (*WindowsAttributes) SetArchive

func (wa *WindowsAttributes) SetArchive(archive bool)

SetArchive sets or clears the archive attribute.

func (*WindowsAttributes) SetHidden

func (wa *WindowsAttributes) SetHidden(hidden bool)

SetHidden sets or clears the hidden attribute.

func (*WindowsAttributes) SetReadOnly

func (wa *WindowsAttributes) SetReadOnly(readonly bool)

SetReadOnly sets or clears the read-only attribute.

func (*WindowsAttributes) SetSystem

func (wa *WindowsAttributes) SetSystem(system bool)

SetSystem sets or clears the system attribute.

func (*WindowsAttributes) String

func (wa *WindowsAttributes) String() string

String returns a human-readable string of the attributes.

Directories

Path Synopsis
Package absfs provides abstract filesystem interfaces.
Package absfs provides abstract filesystem interfaces.
examples
advanced command
basic command
caching command
smb-server command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL