smb2

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Mar 12, 2022 License: BSD-2-Clause Imports: 36 Imported by: 110

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 Walk by fs.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 fs.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
conn, err := net.Dial("tcp", "localhost:445")
if err != nil {
	panic(err)
}
defer conn.Close()

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

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

fs, err := c.Mount(`\\localhost\share`)
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))

// Hello world!
Output:

Index

Examples

Constants

View Source
const MaxReadSizeLimit = 0x100000 // deprecated constant
View Source
const PathSeparator = '\\'

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 added in v1.1.0

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 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 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 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.

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 Session

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

Session represents a SMB session.

func (*Session) ListSharenames added in v1.0.1

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 added in v1.1.0

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

func (*Share) Glob added in v1.1.0

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 TransportError

type TransportError struct {
	Err error
}

TransportError represents a error come from net.Conn layer.

func (*TransportError) Error

func (err *TransportError) Error() string

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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