func opensshOptions(options *Options, commandKind opensshCommandKind) []string { args := append([]string{}, opensshCommonOptions...) if options == nil { options = &Options{} } if len(options.proxyCommand) > 0 { args = append(args, "-o", "ProxyCommand "+utils.CommandString(options.proxyCommand...)) } if !options.passwordAuthAllowed { args = append(args, "-o", "PasswordAuthentication no") } // We must set ServerAliveInterval or the server may // think we've become unresponsive on long running // command executions such as "apt-get upgrade". args = append(args, "-o", "ServerAliveInterval 30") if options.allocatePTY { args = append(args, "-t", "-t") // twice to force } if options.knownHostsFile != "" { args = append(args, "-o", "UserKnownHostsFile "+utils.CommandString(options.knownHostsFile)) } identities := append([]string{}, options.identities...) if pk := PrivateKeyFiles(); len(pk) > 0 { // Add client keys as implicit identities identities = append(identities, pk...) } // If any identities are specified, the // default ones must be explicitly specified. if len(identities) > 0 { // Restrict SSH to only the explicitly provided identity files. // Otherwise we may run out of authentication attempts if the // user has many identity files. args = append(args, "-o", "IdentitiesOnly yes") for _, identity := range defaultIdentities { path, err := utils.NormalizePath(identity) if err != nil { logger.Warningf("failed to normalize path %q: %v", identity, err) continue } if _, err := os.Stat(path); err == nil { identities = append(identities, path) } } } for _, identity := range identities { args = append(args, "-i", identity) } if options.port != 0 { port := fmt.Sprint(options.port) if commandKind == scpKind { // scp uses -P instead of -p (-p means preserve). args = append(args, "-P", port) } else { args = append(args, "-p", port) } } return args }
// Command implements Client.Command. func (c *OpenSSHClient) Command(host string, command []string, options *Options) *Cmd { args := opensshOptions(options, sshKind) args = append(args, host) if len(command) > 0 { args = append(args, command...) } bin, args := sshpassWrap("ssh", args) logger.Debugf("running: %s %s", bin, utils.CommandString(args...)) return &Cmd{impl: &opensshCmd{exec.Command(bin, args...)}} }
func opensshOptions(options *Options, commandKind opensshCommandKind) []string { args := append([]string{}, opensshCommonOptions...) if options == nil { options = &Options{} } if len(options.proxyCommand) > 0 { args = append(args, "-o", "ProxyCommand "+utils.CommandString(options.proxyCommand...)) } if !options.passwordAuthAllowed { args = append(args, "-o", "PasswordAuthentication no") } if options.allocatePTY { args = append(args, "-t", "-t") // twice to force } identities := append([]string{}, options.identities...) if pk := PrivateKeyFiles(); len(pk) > 0 { // Add client keys as implicit identities identities = append(identities, pk...) } // If any identities are specified, the // default ones must be explicitly specified. if len(identities) > 0 { for _, identity := range defaultIdentities { path, err := utils.NormalizePath(identity) if err != nil { logger.Warningf("failed to normalize path %q: %v", identity, err) continue } if _, err := os.Stat(path); err == nil { identities = append(identities, path) } } } for _, identity := range identities { args = append(args, "-i", identity) } if options.port != 0 { port := fmt.Sprint(options.port) if commandKind == scpKind { // scp uses -P instead of -p (-p means preserve). args = append(args, "-P", port) } else { args = append(args, "-p", port) } } return args }
// Copy implements Client.Copy. func (c *OpenSSHClient) Copy(args []string, userOptions *Options) error { var options Options if userOptions != nil { options = *userOptions options.allocatePTY = false // doesn't make sense for scp } allArgs := opensshOptions(&options, scpKind) allArgs = append(allArgs, args...) bin, allArgs := sshpassWrap("scp", allArgs) cmd := exec.Command(bin, allArgs...) var stderr bytes.Buffer cmd.Stderr = &stderr logger.Debugf("running: %s %s", bin, utils.CommandString(args...)) if err := cmd.Run(); err != nil { stderr := strings.TrimSpace(stderr.String()) if len(stderr) > 0 { err = fmt.Errorf("%v (%v)", err, stderr) } return err } return nil }
// Command implements Client.Command. func (c *GoCryptoClient) Command(host string, command []string, options *Options) *Cmd { shellCommand := utils.CommandString(command...) signers := c.signers if len(signers) == 0 { signers = privateKeys() } user, host := splitUserHost(host) port := sshDefaultPort var proxyCommand []string if options != nil { if options.port != 0 { port = options.port } proxyCommand = options.proxyCommand } logger.Tracef(`running (equivalent of): ssh "%s@%s" -p %d '%s'`, user, host, port, shellCommand) return &Cmd{impl: &goCryptoCommand{ signers: signers, user: user, addr: net.JoinHostPort(host, strconv.Itoa(port)), command: shellCommand, proxyCommand: proxyCommand, }} }
func (*utilsSuite) TestCommandString(c *gc.C) { type test struct { args []string expected string } tests := []test{ {nil, ""}, {[]string{"a"}, "a"}, {[]string{"a$"}, `"a\$"`}, {[]string{""}, ""}, {[]string{"\\"}, `"\\"`}, {[]string{"a", "'b'"}, "a 'b'"}, {[]string{"a b"}, `"a b"`}, {[]string{"a", `"b"`}, `a "\"b\""`}, {[]string{"a", `"b\"`}, `a "\"b\\\""`}, {[]string{"a\n"}, "\"a\n\""}, } for i, test := range tests { c.Logf("test %d: %q", i, test.args) result := utils.CommandString(test.args...) c.Assert(result, gc.Equals, test.expected) } } func (*utilsSuite) TestReadSHA256AndReadFileSHA256(c *gc.C) { sha256Tests := []struct { content string sha256 string }{{ content: "", sha256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", }, { content: "some content", sha256: "290f493c44f5d63d06b374d0a5abd292fae38b92cab2fae5efefe1b0e9347f56", }, { content: "foo", sha256: "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", }, { content: "Foo", sha256: "1cbec737f863e4922cee63cc2ebbfaafcd1cff8b790d8cfd2e6a5d550b648afa", }, { content: "multi\nline\ntext\nhere", sha256: "c384f11c0294280792a44d9d6abb81f9fd991904cb7eb851a88311b04114231e", }} tempDir := c.MkDir() for i, test := range sha256Tests { c.Logf("test %d: %q -> %q", i, test.content, test.sha256) buf := bytes.NewBufferString(test.content) hash, size, err := utils.ReadSHA256(buf) c.Check(err, gc.IsNil) c.Check(hash, gc.Equals, test.sha256) c.Check(int(size), gc.Equals, len(test.content)) tempFileName := filepath.Join(tempDir, fmt.Sprintf("sha256-%d", i)) err = ioutil.WriteFile(tempFileName, []byte(test.content), 0644) c.Check(err, gc.IsNil) fileHash, fileSize, err := utils.ReadFileSHA256(tempFileName) c.Check(err, gc.IsNil) c.Check(fileHash, gc.Equals, hash) c.Check(fileSize, gc.Equals, size) } }
func opensshOptions(options *Options, commandKind opensshCommandKind) []string { if options == nil { options = &Options{} } var args []string var hostChecks string switch options.strictHostKeyChecking { case StrictHostChecksYes: hostChecks = "yes" case StrictHostChecksNo: hostChecks = "no" case StrictHostChecksAsk: hostChecks = "ask" default: // StrictHostChecksUnset and invalid values are handled the // same way (the option doesn't get included). } if hostChecks != "" { args = append(args, "-o", "StrictHostKeyChecking "+hostChecks) } if len(options.proxyCommand) > 0 { args = append(args, "-o", "ProxyCommand "+utils.CommandString(options.proxyCommand...)) } if !options.passwordAuthAllowed { args = append(args, "-o", "PasswordAuthentication no") } // We must set ServerAliveInterval or the server may // think we've become unresponsive on long running // command executions such as "apt-get upgrade". args = append(args, "-o", "ServerAliveInterval 30") if options.allocatePTY { args = append(args, "-t", "-t") // twice to force } if options.knownHostsFile != "" { args = append(args, "-o", "UserKnownHostsFile "+utils.CommandString(options.knownHostsFile)) } identities := append([]string{}, options.identities...) if pk := PrivateKeyFiles(); len(pk) > 0 { // Add client keys as implicit identities identities = append(identities, pk...) } // If any identities are specified, the // default ones must be explicitly specified. if len(identities) > 0 { for _, identity := range defaultIdentities { path, err := utils.NormalizePath(identity) if err != nil { logger.Warningf("failed to normalize path %q: %v", identity, err) continue } if _, err := os.Stat(path); err == nil { identities = append(identities, path) } } } for _, identity := range identities { args = append(args, "-i", identity) } if options.port != 0 { port := fmt.Sprint(options.port) if commandKind == scpKind { // scp uses -P instead of -p (-p means preserve). args = append(args, "-P", port) } else { args = append(args, "-p", port) } } return args }