smb

package module
v0.0.0-...-bc8e97d Latest Latest
Warning

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

Go to latest
Published: Mar 8, 2024 License: BSD-2-Clause Imports: 39 Imported by: 0

README

smb2

Build Status Go Reference

Description

SMB2/3 client implementation.

Installation

go get github.com/hirochachacha/go-smb2

Documentation

http://godoc.org/github.com/hirochachacha/go-smb2

Examples

List share names
package main

import (
	"fmt"
	"net"

	"github.com/hirochachacha/go-smb2"
)

func main() {
	conn, err := net.Dial("tcp", "SERVERNAME:445")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	d := &smb2.Dialer{
		Initiator: &smb2.NTLMInitiator{
			User:     "USERNAME",
			Password: "PASSWORD",
		},
	}

	s, err := d.Dial(conn)
	if err != nil {
		panic(err)
	}
	defer s.Logoff()

	names, err := s.ListSharenames()
	if err != nil {
		panic(err)
	}

	for _, name := range names {
		fmt.Println(name)
	}
}
File manipulation
package main

import (
	"io"
	"io/ioutil"
	"net"

	"github.com/hirochachacha/go-smb2"
)

func main() {
	conn, err := net.Dial("tcp", "SERVERNAME:445")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	d := &smb2.Dialer{
		Initiator: &smb2.NTLMInitiator{
			User:     "USERNAME",
			Password: "PASSWORD",
		},
	}

	s, err := d.Dial(conn)
	if err != nil {
		panic(err)
	}
	defer s.Logoff()

	fs, err := s.Mount("SHARENAME")
	if err != nil {
		panic(err)
	}
	defer fs.Umount()

	f, err := fs.Create("hello.txt")
	if err != nil {
		panic(err)
	}
	defer fs.Remove("hello.txt")
	defer f.Close()

	_, err = f.Write([]byte("Hello world!"))
	if err != nil {
		panic(err)
	}

	_, err = f.Seek(0, io.SeekStart)
	if err != nil {
		panic(err)
	}

	bs, err := ioutil.ReadAll(f)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(bs))
}
Check error types
package main

import (
	"context"
	"fmt"
	"net"
	"os"

	"github.com/hirochachacha/go-smb2"
)

func main() {
	conn, err := net.Dial("tcp", "SERVERNAME:445")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	d := &smb2.Dialer{
		Initiator: &smb2.NTLMInitiator{
			User:     "USERNAME",
			Password: "PASSWORD",
		},
	}

	s, err := d.Dial(conn)
	if err != nil {
		panic(err)
	}
	defer s.Logoff()

	fs, err := s.Mount("SHARENAME")
	if err != nil {
		panic(err)
	}
	defer fs.Umount()

	_, err = fs.Open("notExist.txt")

	fmt.Println(os.IsNotExist(err)) // true
	fmt.Println(os.IsExist(err))    // false

	fs.WriteFile("hello2.txt", []byte("test"), 0444)
	err = fs.WriteFile("hello2.txt", []byte("test2"), 0444)
	fmt.Println(os.IsPermission(err)) // true

	ctx, cancel := context.WithTimeout(context.Background(), 0)
	defer cancel()

	_, err = fs.WithContext(ctx).Open("hello.txt")

	fmt.Println(os.IsTimeout(err)) // true
}
Glob and WalkDir through FS interface
package main

import (
	"fmt"
	"net"
	iofs "io/fs"

	"github.com/hirochachacha/go-smb2"
)

func main() {
	conn, err := net.Dial("tcp", "SERVERNAME:445")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	d := &smb2.Dialer{
		Initiator: &smb2.NTLMInitiator{
			User:     "USERNAME",
			Password: "PASSWORD",
		},
	}

	s, err := d.Dial(conn)
	if err != nil {
		panic(err)
	}
	defer s.Logoff()

	fs, err := s.Mount("SHARENAME")
	if err != nil {
		panic(err)
	}
	defer fs.Umount()

	matches, err := iofs.Glob(fs.DirFS("."), "*")
	if err != nil {
		panic(err)
	}
	for _, match := range matches {
		fmt.Println(match)
	}

	err = iofs.WalkDir(fs.DirFS("."), ".", func(path string, d iofs.DirEntry, err error) error {
		fmt.Println(path, d, err)

		return nil
	})
	if err != nil {
		panic(err)
	}
}

Documentation

Overview

Package smb2 implements the SMB2/3 client in [MS-SMB2].

https://msdn.microsoft.com/en-us/library/cc246482.aspx

This package doesn't support CAP_UNIX extension. Symlink is supported by FSCTL_SET_REPARSE_POINT and FSCTL_GET_REPARSE_POINT. The symlink-following algorithm is explained in 2.2.2.2.1 and 2.2.2.2.1.1.

https://msdn.microsoft.com/en-us/library/cc246542.aspx

Supported features and protocol versions are declared in feature.go.

Example
package main

import (
	"fmt"
	"io"
	"net"

	"github.com/5amu/smb"
)

func main() {
	conn, err := net.Dial("tcp", "localhost:445")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	d := &smb.Dialer{
		Initiator: &smb.NTLMInitiator{
			User:     "Guest",
			Password: "",
			Domain:   "MicrosoftAccount",
		},
	}

	c, err := d.Dial(conn)
	if err != nil {
		panic(err)
	}
	defer func() {
		_ = c.Logoff()
	}()

	fs, err := c.Mount(`\\localhost\share`)
	if err != nil {
		panic(err)
	}
	defer func() {
		_ = fs.Umount()
	}()

	f, err := fs.Create("hello.txt")
	if err != nil {
		panic(err)
	}
	defer func() {
		_ = fs.Remove("hello.txt")
		_ = f.Close()
	}()

	_, err = f.Write([]byte("Hello world!"))
	if err != nil {
		panic(err)
	}

	_, err = f.Seek(0, io.SeekStart)
	if err != nil {
		panic(err)
	}

	bs, err := io.ReadAll(f)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(bs))

	// Hello world!
}
Output:

Index

Examples

Constants

View Source
const DialectSmb_1_0 = "\x02NT LM 0.12\x00"
View Source
const MaxReadSizeLimit = 0x100000 // deprecated constant
View Source
const PathSeparator = '\\'
View Source
const ProtocolSmb = "\xFFSMB"

SMBv1 is supported as far as DETECTION goes. In 2024 I'm not willing to fully support it... I guess that help would be appreciated wut not actively wanted. Thank you for your understanding.

Variables

View Source
var ErrBadPattern = errors.New("syntax error in pattern")

ErrBadPattern indicates a pattern was malformed.

View Source
var NORMALIZE_PATH = true // normalize path arguments automatically

Functions

func IsPathSeparator

func IsPathSeparator(c uint8) bool

func Match

func Match(pattern, name string) (matched bool, err error)

Match reports whether name matches the shell file name pattern. The pattern syntax is:

pattern:
	{ term }
term:
	'*'         matches any sequence of non-Separator characters
	'?'         matches any single non-Separator character
	'[' [ '^' ] { character-range } ']'
	            character class (must be non-empty)
	c           matches character c (c != '*', '?', '[')

character-range:
	c           matches character c (c != '-', ']')
	lo '-' hi   matches character c for lo <= c <= hi

Match requires pattern to match all of name, not just a substring. The only possible returned error is ErrBadPattern, when pattern is malformed.

Types

type BinaryMarshallableV1

type BinaryMarshallableV1 interface {
	MarshalBinary(*MetadataV1) ([]byte, error)
	UnmarshalBinary([]byte, *MetadataV1) error
}

type Client

type Client = Session // deprecated type name

type ContextError

type ContextError struct {
	Err error
}

ContextError wraps a context error to support os.IsTimeout function.

func (*ContextError) Error

func (err *ContextError) Error() string

func (*ContextError) Timeout

func (err *ContextError) Timeout() bool

type Dialer

type Dialer struct {
	MaxCreditBalance uint16 // if it's zero, clientMaxCreditBalance is used. (See feature.go for more details)
	Negotiator       Negotiator
	Initiator        Initiator
}

Dialer contains options for func (*Dialer) Dial.

func (*Dialer) Dial

func (d *Dialer) Dial(tcpConn net.Conn) (*Session, error)

Dial performs negotiation and authentication. It returns a session. It doesn't support NetBIOS transport. This implementation doesn't support multi-session on the same TCP connection. If you want to use another session, you need to prepare another TCP connection at first.

func (*Dialer) DialContext

func (d *Dialer) DialContext(ctx context.Context, tcpConn net.Conn) (*Session, error)

DialContext performs negotiation and authentication using the provided context. Note that returned session doesn't inherit context. If you want to use the same context, call Session.WithContext manually. This implementation doesn't support multi-session on the same TCP connection. If you want to use another session, you need to prepare another TCP connection at first.

type File

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

func (*File) Chmod

func (f *File) Chmod(mode os.FileMode) error

func (*File) Close

func (f *File) Close() error

func (*File) Name

func (f *File) Name() string

func (*File) Read

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

func (*File) ReadAt

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

ReadAt implements io.ReaderAt.

func (*File) ReadFrom

func (f *File) ReadFrom(r io.Reader) (n int64, err error)

ReadFrom implements io.ReadFrom. If r is *File on the same *Share as f, it invokes server-side copy.

func (*File) Readdir

func (f *File) Readdir(n int) (fi []os.FileInfo, err error)

func (*File) Readdirnames

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

func (*File) Seek

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

Seek implements io.Seeker.

func (*File) Stat

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

func (*File) Statfs

func (f *File) Statfs() (FileFsInfo, error)

func (*File) Sync

func (f *File) Sync() (err error)

func (*File) Truncate

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

func (*File) Write

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

func (*File) WriteAt

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

WriteAt implements io.WriterAt.

func (*File) WriteString

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

func (*File) WriteTo

func (f *File) WriteTo(w io.Writer) (n int64, err error)

WriteTo implements io.WriteTo. If w is *File on the same *Share as f, it invokes server-side copy.

type FileFsInfo

type FileFsInfo interface {
	BlockSize() uint64
	FragmentSize() uint64
	TotalBlockCount() uint64
	FreeBlockCount() uint64
	AvailableBlockCount() uint64
}

type FileStat

type FileStat struct {
	CreationTime   time.Time
	LastAccessTime time.Time
	LastWriteTime  time.Time
	ChangeTime     time.Time
	EndOfFile      int64
	AllocationSize int64
	FileAttributes uint32
	FileName       string
}

func (*FileStat) IsDir

func (fs *FileStat) IsDir() bool

func (*FileStat) ModTime

func (fs *FileStat) ModTime() time.Time

func (*FileStat) Mode

func (fs *FileStat) Mode() os.FileMode

func (*FileStat) Name

func (fs *FileStat) Name() string

func (*FileStat) Size

func (fs *FileStat) Size() int64

func (*FileStat) Sys

func (fs *FileStat) Sys() interface{}

type HeaderV1

type HeaderV1 struct {
	ProtocolID       []byte `smb:"fixed:4"`
	Command          uint8
	Status           uint32
	Flags            uint8
	Flags2           uint16
	PIDHigh          uint16
	SecurityFeatures []byte `smb:"fixed:8"`
	Reserved         uint16
	TID              uint16
	PIDLow           uint16
	UID              uint16
	MID              uint16
}

type Initiator

type Initiator interface {
	// contains filtered or unexported methods
}

type InternalError

type InternalError struct {
	Message string
}

InternalError represents internal error.

func (*InternalError) Error

func (err *InternalError) Error() string

type InvalidResponseError

type InvalidResponseError struct {
	Message string
}

InvalidResponseError represents a data sent by the server is corrupted or unexpected.

func (*InvalidResponseError) Error

func (err *InvalidResponseError) Error() string

type MetadataV1

type MetadataV1 struct {
	Tags       *TagMapV1
	Lens       map[string]uint64
	Offsets    map[string]uint64
	Parent     interface{}
	ParentBuf  []byte
	CurrOffset uint64
	CurrField  string
}

type NTLMInitiator

type NTLMInitiator struct {
	User        string
	Password    string
	Hash        []byte
	Domain      string
	Workstation string
	TargetSPN   string
	// contains filtered or unexported fields
}

NTLMInitiator implements session-setup through NTLMv2. It doesn't support NTLMv1. You can use Hash instead of Password.

func (*NTLMInitiator) InfoMap

func (i *NTLMInitiator) InfoMap() *ntlm.InfoMap

type NTLMSSPInfoMap

type NTLMSSPInfoMap struct {
	NbComputerName  string
	NbDomainName    string
	DnsComputerName string
	DnsDomainName   string
	DnsTreeName     string
}

type NTLMSSPInitiator

type NTLMSSPInitiator struct {
	User        string
	Password    string
	Hash        []byte
	Domain      string
	Workstation string
	TargetSPN   string
	// contains filtered or unexported fields
}

func (*NTLMSSPInitiator) GetInfoMap

func (i *NTLMSSPInitiator) GetInfoMap() *NTLMSSPInfoMap

type NegotiateReqV1

type NegotiateReqV1 struct {
	HeaderV1
	WordCount uint8
	ByteCount uint16  // hardcoded to 14
	Dialects  []uint8 `smb:"fixed:12"`
}

type Negotiator

type Negotiator struct {
	RequireMessageSigning bool     // enforce signing?
	ClientGuid            [16]byte // if it's zero, generated by crypto/rand.
	SpecifiedDialect      uint16   // if it's zero, clientDialects is used. (See feature.go for more details)
}

Negotiator contains options for func (*Dialer) Dial.

type RemoteFile

type RemoteFile = File // deprecated type name

type RemoteFileStat

type RemoteFileStat = FileStat // deprecated type name

type RemoteFileSystem

type RemoteFileSystem = Share // deprecated type name

type ResponseError

type ResponseError struct {
	Code uint32 // NTSTATUS
	// contains filtered or unexported fields
}

ResponseError represents a error with a nt status code sent by the server. The NTSTATUS is defined in [MS-ERREF]. https://msdn.microsoft.com/en-au/library/cc704588.aspx

func (*ResponseError) Error

func (err *ResponseError) Error() string

type SMBFingerprint

type SMBFingerprint struct {
	// V1Support if supports SMBv1
	V1Support bool

	// Security Mode of the connection
	SigningRequired bool

	// Reported Vesion of OS
	OSVersion string

	// NETBIOS
	NetBIOSComputerName string
	NetBIOSDomainName   string

	// DNS
	DNSComputerName string
	DNSDomainName   string
	ForestName      string
}

func Fingerprint

func Fingerprint(host string, port int) (*SMBFingerprint, error)

func FingerprintWithDialer

func FingerprintWithDialer(host string, port int, dialer func(network string, addr string) (net.Conn, error)) (*SMBFingerprint, error)

type Session

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

Session represents a SMB session.

func (*Session) ListSharenames

func (c *Session) ListSharenames() ([]string, error)

func (*Session) Logoff

func (c *Session) Logoff() error

Logoff invalidates the current SMB session.

func (*Session) Mount

func (c *Session) Mount(sharename string) (*Share, error)

Mount mounts the SMB share. sharename must follow format like `<share>` or `\\<server>\<share>`. Note that the mounted share doesn't inherit session's context. If you want to use the same context, call Share.WithContext manually.

func (*Session) WithContext

func (c *Session) WithContext(ctx context.Context) *Session

type Share

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

Share represents a SMB tree connection with VFS interface.

func (*Share) Chmod

func (fs *Share) Chmod(name string, mode os.FileMode) error

func (*Share) Chtimes

func (fs *Share) Chtimes(name string, atime time.Time, mtime time.Time) error

func (*Share) Create

func (fs *Share) Create(name string) (*File, error)

func (*Share) DirFS

func (s *Share) DirFS(dirname string) fs.FS

func (*Share) Glob

func (fs *Share) Glob(pattern string) (matches []string, err error)

Glob should work like filepath.Glob.

func (*Share) Lstat

func (fs *Share) Lstat(name string) (os.FileInfo, error)

func (*Share) Mkdir

func (fs *Share) Mkdir(name string, perm os.FileMode) error

func (*Share) MkdirAll

func (fs *Share) MkdirAll(path string, perm os.FileMode) error

MkdirAll mimics os.MkdirAll

func (*Share) Open

func (fs *Share) Open(name string) (*File, error)

func (*Share) OpenFile

func (fs *Share) OpenFile(name string, flag int, perm os.FileMode) (*File, error)

func (*Share) ReadDir

func (fs *Share) ReadDir(dirname string) ([]os.FileInfo, error)

func (*Share) ReadFile

func (fs *Share) ReadFile(filename string) ([]byte, error)
func (fs *Share) Readlink(name string) (string, error)

func (*Share) Remove

func (fs *Share) Remove(name string) error

func (*Share) RemoveAll

func (fs *Share) RemoveAll(path string) error

RemoveAll removes path and any children it contains. It removes everything it can but returns the first error it encounters. If the path does not exist, RemoveAll returns nil (no error).

func (*Share) Rename

func (fs *Share) Rename(oldpath, newpath string) error

func (*Share) Stat

func (fs *Share) Stat(name string) (os.FileInfo, error)

func (*Share) Statfs

func (fs *Share) Statfs(name string) (FileFsInfo, error)
func (fs *Share) Symlink(target, linkpath string) error

Symlink mimics os.Symlink. This API should work on latest Windows and latest MacOS. However it may not work on Linux because Samba doesn't support reparse point well. Also there is a restriction on target pathname. Generally, a pathname begins with leading backslash (e.g `\dir\name`) can be interpreted as two ways. On windows, it is evaluated as a relative path, on other systems, it is evaluated as an absolute path. This implementation always assumes that format is absolute path. So, if you know the target server is Windows, you should avoid that format. If you want to use an absolute target path on windows, you can use // `C:\dir\name` format instead.

func (*Share) Truncate

func (fs *Share) Truncate(name string, size int64) error

func (*Share) Umount

func (fs *Share) Umount() error

Umount disconects the current SMB tree.

func (*Share) WithContext

func (fs *Share) WithContext(ctx context.Context) *Share

func (*Share) WriteFile

func (fs *Share) WriteFile(filename string, data []byte, perm os.FileMode) error

type TagMapV1

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

func (TagMapV1) Get

func (t TagMapV1) Get(key string) interface{}

func (TagMapV1) GetInt

func (t TagMapV1) GetInt(key string) (int, error)

func (TagMapV1) GetString

func (t TagMapV1) GetString(key string) (string, error)

func (TagMapV1) Has

func (t TagMapV1) Has(key string) bool

func (TagMapV1) Set

func (t TagMapV1) Set(key string, val interface{})

type TransportError

type TransportError struct {
	Err error
}

TransportError represents a error come from net.Conn layer.

func (*TransportError) Error

func (err *TransportError) Error() string

type V1Client

type V1Client struct {
	Host string
	Port int
	Conn net.Conn
	// contains filtered or unexported fields
}

func NewV1Client

func NewV1Client() *V1Client

func (*V1Client) IsSMBv1

func (c *V1Client) IsSMBv1() bool

func (*V1Client) WithConn

func (c *V1Client) WithConn(conn net.Conn) *V1Client

func (*V1Client) WithHostPort

func (c *V1Client) WithHostPort(host string, port int) *V1Client

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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