diff --git a/sftp/common/sftp.go b/sftp/common/sftp.go index dd1222c1..bde968db 100644 --- a/sftp/common/sftp.go +++ b/sftp/common/sftp.go @@ -1,3 +1,5 @@ +//go:build !windows + package common import ( diff --git a/sftp/common/sftp_windows.go b/sftp/common/sftp_windows.go new file mode 100644 index 00000000..5eeabb49 --- /dev/null +++ b/sftp/common/sftp_windows.go @@ -0,0 +1,109 @@ +package common + +import ( + "bufio" + "fmt" + "net/url" + "os/exec" + "strings" + + "github.com/pkg/sftp" +) + +func CheckParamSupport(params map[string]string) error { + for _, key := range []string{"ssh_auth_sock", "ssh_private_key", "ssh_private_key_ttl"} { + if _, exists := params[key]; exists { + return fmt.Errorf("%q not support on Windows", key) + } + } + + return nil +} + +func Connect(endpoint *url.URL, params map[string]string) (*sftp.Client, error) { + if endpoint == nil { + return nil, fmt.Errorf("nil endpoint") + } + + host := endpoint.Hostname() + if host == "" { + return nil, fmt.Errorf("missing hostname in endpoint: %q", endpoint.String()) + } + + if err := CheckParamSupport(params); err != nil { + return nil, err + } + + var args []string + + args = append(args, "-o", "BatchMode=yes") + + if params["insecure_ignore_host_key"] == "true" { + args = append(args, "-o", "StrictHostKeyChecking=no") + } + + if id := params["identity"]; id != "" { + args = append(args, "-i", id) + } + + // username resolution: forbid both user@host AND username param + if endpoint.User != nil && params["username"] != "" { + return nil, fmt.Errorf("can not use user@host foo syntax and username parameter") + } else if endpoint.User != nil { + args = append(args, "-l", endpoint.User.Username()) + } else if params["username"] != "" { + args = append(args, "-l", params["username"]) + } + + if p := endpoint.Port(); p != "" { + args = append(args, "-p", p) + } + + args = append(args, host) + args = append(args, "-s", "sftp") + + cmd := exec.Command("ssh", args...) + + stderr, err := cmd.StderrPipe() + if err != nil { + return nil, err + } + + var sshErr error + go func() { + sc := bufio.NewScanner(stderr) + for sc.Scan() { + line := sc.Text() + if strings.HasPrefix(line, "Warning:") { + continue + } + sshErr = fmt.Errorf("ssh command error: %q", line) + } + }() + + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + stdin, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + + if err := cmd.Start(); err != nil { + return nil, err + } + + // reap process + go func() { _ = cmd.Wait() }() + + client, err := sftp.NewClientPipe(stdout, stdin) + if err != nil { + if sshErr != nil { + return nil, sshErr + } + return nil, err + } + + return client, nil +} diff --git a/sftp/exporter/schema.json b/sftp/exporter/schema.json index 4ea1c118..0612aafe 100644 --- a/sftp/exporter/schema.json +++ b/sftp/exporter/schema.json @@ -44,17 +44,17 @@ "ssh_auth_sock": { "type": "string", "minLength": 1, - "description": "Path to SSH agent socket (exported as SSH_AUTH_SOCK for ssh/ssh-add)" + "description": "Path to SSH agent socket (exported as SSH_AUTH_SOCK for ssh/ssh-add) (not supported on Windows)" }, "ssh_private_key": { "type": "string", "minLength": 1, - "description": "SSH private key material (PEM/OpenSSH) to load into ssh-agent via ssh-add -" + "description": "SSH private key material (PEM/OpenSSH) to load into ssh-agent via ssh-add - (not supported on Windows)" }, "ssh_private_key_ttl": { "type": "string", "default": "5s", - "description": "TTL for ssh-add -t (e.g. 5s, 1m, 1h)" + "description": "TTL for ssh-add -t (e.g. 5s, 1m, 1h) (not supported on Windows)" } }, "allOf": [ diff --git a/sftp/importer/schema.json b/sftp/importer/schema.json index 076ebf12..0a90133c 100644 --- a/sftp/importer/schema.json +++ b/sftp/importer/schema.json @@ -44,17 +44,17 @@ "ssh_auth_sock": { "type": "string", "minLength": 1, - "description": "Path to SSH agent socket (exported as SSH_AUTH_SOCK for ssh/ssh-add)" + "description": "Path to SSH agent socket (exported as SSH_AUTH_SOCK for ssh/ssh-add) (not supported on Windows)" }, "ssh_private_key": { "type": "string", "minLength": 1, - "description": "SSH private key material (PEM/OpenSSH) to load into ssh-agent via ssh-add -" + "description": "SSH private key material (PEM/OpenSSH) to load into ssh-agent via ssh-add - (not supported on Windows)" }, "ssh_private_key_ttl": { "type": "string", "default": "5s", - "description": "TTL for ssh-add -t (e.g. 5s, 1m, 1h)" + "description": "TTL for ssh-add -t (e.g. 5s, 1m, 1h) (not supported on Windows)" } }, "allOf": [ diff --git a/sftp/storage/schema.json b/sftp/storage/schema.json index 9eb69049..0903ffa3 100644 --- a/sftp/storage/schema.json +++ b/sftp/storage/schema.json @@ -39,17 +39,17 @@ "insecure_ignore_host_key": { "type": "boolean", "default": false, - "description": "Disable host key verification (ssh StrictHostKeyChecking=no) (dangerous; use only for testing)" + "description": "Disable host key verification (ssh StrictHostKeyChecking=no) (dangerous; use only for testing) (not supported on Windows)" }, "ssh_auth_sock": { "type": "string", "minLength": 1, - "description": "Path to SSH agent socket (exported as SSH_AUTH_SOCK for ssh/ssh-add)" + "description": "Path to SSH agent socket (exported as SSH_AUTH_SOCK for ssh/ssh-add) (not supported on Windows)" }, "ssh_private_key": { "type": "string", "minLength": 1, - "description": "SSH private key material (PEM/OpenSSH) to load into ssh-agent via ssh-add -" + "description": "SSH private key material (PEM/OpenSSH) to load into ssh-agent via ssh-add - (not supported on Windows)" }, "ssh_private_key_ttl": { "type": "string",