restic/internal/backend/smb/config.go

100 lines
3.6 KiB
Go

package smb
import (
"path"
"strconv"
"strings"
"time"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/options"
)
// Config contains all configuration necessary to connect to an SMB server
type Config struct {
Address string
Port int
ShareName string
Path string
User string `option:"user" help:"specify the SMB user for NTLM authentication."`
Password options.SecretString `option:"password" help:"specify the SMB password for NTLM authentication."`
Domain string `option:"domain" help:"specify the domain for authentication."`
Layout string `option:"layout" help:"use this backend directory layout (default: auto-detect)"`
Connections uint `option:"connections" help:"set a limit for the number of concurrent operations (default: 2)"`
IdleTimeout time.Duration `option:"idle-timeout" help:"Max time in seconds before closing idle connections. If no connections have been returned to the connection pool in the time given, the connection pool will be emptied. Set to 0 to keep connections indefinitely.(default: 60)"`
RequireMessageSigning bool `option:"require-message-signing" help:"Mandates message signing otherwise does not allow the connection. If this is false, messaging signing is just enabled and not enforced. (default: false)"`
Dialect uint16 `option:"dialect" help:"Force a specific dialect to be used. SMB311:785, SMB302:770, SMB300:768, SMB210:528, SMB202:514, SMB2:767. If unspecfied (0), following dialects are tried in order - SMB311, SMB302, SMB300, SMB210, SMB202 (default: 0)"`
ClientGuid string `option:"client-guid" help:"A 16-byte GUID to uniquely identify a client. If not specific a random GUID is used. (default: \"\")"`
}
const (
DefaultSmbPort int = 445
DefaultDomain string = "WORKGROUP"
DefaultConnections uint = 2
DefaultIdleTimeout time.Duration = 60 * time.Second
)
// NewConfig returns a new Config with the default values filled in.
func NewConfig() Config {
return Config{
Port: DefaultSmbPort,
Domain: DefaultDomain,
IdleTimeout: DefaultIdleTimeout,
Connections: DefaultConnections,
}
}
func init() {
options.Register("smb", Config{})
}
// ParseConfig parses the string s and extracts the s3 config. The two
// supported configuration formats are smb://address:port/sharename/directory and
// smb://address/sharename/directory in which case default port 445 is used.
// If no prefix is given the prefix "restic" will be used.
func ParseConfig(s string) (interface{}, error) {
switch {
case strings.HasPrefix(s, "smb://"):
s = s[6:]
case strings.HasPrefix(s, "smb:"):
s = s[4:]
default:
return nil, errors.New("smb: invalid format")
}
// use the first entry of the path as the endpoint and the
// remainder as bucket name and prefix
fullAddress, rest, _ := strings.Cut(s, "/")
address, portString, hasPort := strings.Cut(fullAddress, ":")
var port int
if !hasPort {
port = DefaultSmbPort
} else {
var err error
port, err = strconv.Atoi(portString)
if err != nil {
return nil, err
}
}
sharename, directory, _ := strings.Cut(rest, "/")
return createConfig(address, port, sharename, directory)
}
func createConfig(address string, port int, sharename string, directory string) (interface{}, error) {
if address == "" {
return nil, errors.New("smb: invalid format, address not found")
}
if directory != "" {
directory = path.Clean(directory)
}
cfg := NewConfig()
cfg.Address = address
cfg.Port = port
cfg.ShareName = sharename
cfg.Path = directory
return cfg, nil
}