From 96eab1202717e073782ec399a4e0820cae15b1bb Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Thu, 17 Aug 2017 17:19:06 -0700 Subject: Updating server dependancies. (#7246) --- vendor/golang.org/x/crypto/ssh/agent/client.go | 38 +++++++-- .../golang.org/x/crypto/ssh/agent/client_test.go | 63 ++++++++++---- vendor/golang.org/x/crypto/ssh/agent/server.go | 90 ++++++++++++++++++-- .../golang.org/x/crypto/ssh/agent/server_test.go | 52 +++++++++++- vendor/golang.org/x/crypto/ssh/server.go | 2 +- vendor/golang.org/x/crypto/ssh/session.go | 20 +++++ .../golang.org/x/crypto/ssh/terminal/util_bsd.go | 6 +- .../golang.org/x/crypto/ssh/terminal/util_linux.go | 9 +- .../x/crypto/ssh/terminal/util_windows.go | 99 +++++----------------- .../golang.org/x/crypto/ssh/test/session_test.go | 48 +++++++++++ 10 files changed, 309 insertions(+), 118 deletions(-) (limited to 'vendor/golang.org/x/crypto/ssh') diff --git a/vendor/golang.org/x/crypto/ssh/agent/client.go b/vendor/golang.org/x/crypto/ssh/agent/client.go index ecfd7c58d..dce7682fa 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/client.go +++ b/vendor/golang.org/x/crypto/ssh/agent/client.go @@ -57,6 +57,17 @@ type Agent interface { Signers() ([]ssh.Signer, error) } +// ConstraintExtension describes an optional constraint defined by users. +type ConstraintExtension struct { + // ExtensionName consist of a UTF-8 string suffixed by the + // implementation domain following the naming scheme defined + // in Section 4.2 of [RFC4251], e.g. "foo@example.com". + ExtensionName string + // ExtensionDetails contains the actual content of the extended + // constraint. + ExtensionDetails []byte +} + // AddedKey describes an SSH key to be added to an Agent. type AddedKey struct { // PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey or @@ -73,6 +84,9 @@ type AddedKey struct { // ConfirmBeforeUse, if true, requests that the agent confirm with the // user before each use of this key. ConfirmBeforeUse bool + // ConstraintExtensions are the experimental or private-use constraints + // defined by users. + ConstraintExtensions []ConstraintExtension } // See [PROTOCOL.agent], section 3. @@ -94,8 +108,9 @@ const ( agentAddSmartcardKeyConstrained = 26 // 3.7 Key constraint identifiers - agentConstrainLifetime = 1 - agentConstrainConfirm = 2 + agentConstrainLifetime = 1 + agentConstrainConfirm = 2 + agentConstrainExtension = 3 ) // maxAgentResponseBytes is the maximum agent reply size that is accepted. This @@ -151,6 +166,19 @@ type publicKey struct { Rest []byte `ssh:"rest"` } +// 3.7 Key constraint identifiers +type constrainLifetimeAgentMsg struct { + LifetimeSecs uint32 `sshtype:"1"` +} + +type constrainExtensionAgentMsg struct { + ExtensionName string `sshtype:"3"` + ExtensionDetails []byte + + // Rest is a field used for parsing, not part of message + Rest []byte `ssh:"rest"` +} + // Key represents a protocol 2 public key as defined in // [PROTOCOL.agent], section 2.5.2. type Key struct { @@ -542,11 +570,7 @@ func (c *client) Add(key AddedKey) error { var constraints []byte if secs := key.LifetimeSecs; secs != 0 { - constraints = append(constraints, agentConstrainLifetime) - - var secsBytes [4]byte - binary.BigEndian.PutUint32(secsBytes[:], secs) - constraints = append(constraints, secsBytes[:]...) + constraints = append(constraints, ssh.Marshal(constrainLifetimeAgentMsg{secs})...) } if key.ConfirmBeforeUse { diff --git a/vendor/golang.org/x/crypto/ssh/agent/client_test.go b/vendor/golang.org/x/crypto/ssh/agent/client_test.go index 5fc47e577..a5b20f551 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/client_test.go +++ b/vendor/golang.org/x/crypto/ssh/agent/client_test.go @@ -19,8 +19,8 @@ import ( "golang.org/x/crypto/ssh" ) -// startAgent executes ssh-agent, and returns a Agent interface to it. -func startAgent(t *testing.T) (client Agent, socket string, cleanup func()) { +// startOpenSSHAgent executes ssh-agent, and returns a Agent interface to it. +func startOpenSSHAgent(t *testing.T) (client Agent, socket string, cleanup func()) { if testing.Short() { // ssh-agent is not always available, and the key // types supported vary by platform. @@ -79,16 +79,32 @@ func startAgent(t *testing.T) (client Agent, socket string, cleanup func()) { } } -func testAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { - agent, _, cleanup := startAgent(t) +// startKeyringAgent uses Keyring to simulate a ssh-agent Server and returns a client. +func startKeyringAgent(t *testing.T) (client Agent, cleanup func()) { + c1, c2, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + go ServeAgent(NewKeyring(), c2) + + return NewClient(c1), func() { + c1.Close() + c2.Close() + } +} + +func testOpenSSHAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { + agent, _, cleanup := startOpenSSHAgent(t) defer cleanup() testAgentInterface(t, agent, key, cert, lifetimeSecs) } -func testKeyring(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { - a := NewKeyring() - testAgentInterface(t, a, key, cert, lifetimeSecs) +func testKeyringAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { + agent, cleanup := startKeyringAgent(t) + defer cleanup() + + testAgentInterface(t, agent, key, cert, lifetimeSecs) } func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { @@ -159,8 +175,8 @@ func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Ce func TestAgent(t *testing.T) { for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} { - testAgent(t, testPrivateKeys[keyType], nil, 0) - testKeyring(t, testPrivateKeys[keyType], nil, 1) + testOpenSSHAgent(t, testPrivateKeys[keyType], nil, 0) + testKeyringAgent(t, testPrivateKeys[keyType], nil, 0) } } @@ -172,8 +188,8 @@ func TestCert(t *testing.T) { } cert.SignCert(rand.Reader, testSigners["ecdsa"]) - testAgent(t, testPrivateKeys["rsa"], cert, 0) - testKeyring(t, testPrivateKeys["rsa"], cert, 1) + testOpenSSHAgent(t, testPrivateKeys["rsa"], cert, 0) + testKeyringAgent(t, testPrivateKeys["rsa"], cert, 0) } // netPipe is analogous to net.Pipe, but it uses a real net.Conn, and @@ -203,7 +219,7 @@ func netPipe() (net.Conn, net.Conn, error) { } func TestAuth(t *testing.T) { - agent, _, cleanup := startAgent(t) + agent, _, cleanup := startOpenSSHAgent(t) defer cleanup() a, b, err := netPipe() @@ -247,8 +263,14 @@ func TestAuth(t *testing.T) { conn.Close() } -func TestLockClient(t *testing.T) { - agent, _, cleanup := startAgent(t) +func TestLockOpenSSHAgent(t *testing.T) { + agent, _, cleanup := startOpenSSHAgent(t) + defer cleanup() + testLockAgent(agent, t) +} + +func TestLockKeyringAgent(t *testing.T) { + agent, cleanup := startKeyringAgent(t) defer cleanup() testLockAgent(agent, t) } @@ -308,10 +330,19 @@ func testLockAgent(agent Agent, t *testing.T) { } } -func TestAgentLifetime(t *testing.T) { - agent, _, cleanup := startAgent(t) +func testOpenSSHAgentLifetime(t *testing.T) { + agent, _, cleanup := startOpenSSHAgent(t) defer cleanup() + testAgentLifetime(t, agent) +} + +func testKeyringAgentLifetime(t *testing.T) { + agent, cleanup := startKeyringAgent(t) + defer cleanup() + testAgentLifetime(t, agent) +} +func testAgentLifetime(t *testing.T, agent Agent) { for _, keyType := range []string{"rsa", "dsa", "ecdsa"} { // Add private keys to the agent. err := agent.Add(AddedKey{ diff --git a/vendor/golang.org/x/crypto/ssh/agent/server.go b/vendor/golang.org/x/crypto/ssh/agent/server.go index 68a333fa5..321e48a26 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/server.go +++ b/vendor/golang.org/x/crypto/ssh/agent/server.go @@ -106,7 +106,7 @@ func (s *server) processRequest(data []byte) (interface{}, error) { return nil, s.agent.Lock(req.Passphrase) case agentUnlock: - var req agentLockMsg + var req agentUnlockMsg if err := ssh.Unmarshal(data, &req); err != nil { return nil, err } @@ -155,6 +155,44 @@ func (s *server) processRequest(data []byte) (interface{}, error) { return nil, fmt.Errorf("unknown opcode %d", data[0]) } +func parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmBeforeUse bool, extensions []ConstraintExtension, err error) { + for len(constraints) != 0 { + switch constraints[0] { + case agentConstrainLifetime: + lifetimeSecs = binary.BigEndian.Uint32(constraints[1:5]) + constraints = constraints[5:] + case agentConstrainConfirm: + confirmBeforeUse = true + constraints = constraints[1:] + case agentConstrainExtension: + var msg constrainExtensionAgentMsg + if err = ssh.Unmarshal(constraints, &msg); err != nil { + return 0, false, nil, err + } + extensions = append(extensions, ConstraintExtension{ + ExtensionName: msg.ExtensionName, + ExtensionDetails: msg.ExtensionDetails, + }) + constraints = msg.Rest + default: + return 0, false, nil, fmt.Errorf("unknown constraint type: %d", constraints[0]) + } + } + return +} + +func setConstraints(key *AddedKey, constraintBytes []byte) error { + lifetimeSecs, confirmBeforeUse, constraintExtensions, err := parseConstraints(constraintBytes) + if err != nil { + return err + } + + key.LifetimeSecs = lifetimeSecs + key.ConfirmBeforeUse = confirmBeforeUse + key.ConstraintExtensions = constraintExtensions + return nil +} + func parseRSAKey(req []byte) (*AddedKey, error) { var k rsaKeyMsg if err := ssh.Unmarshal(req, &k); err != nil { @@ -173,7 +211,11 @@ func parseRSAKey(req []byte) (*AddedKey, error) { } priv.Precompute() - return &AddedKey{PrivateKey: priv, Comment: k.Comments}, nil + addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil } func parseEd25519Key(req []byte) (*AddedKey, error) { @@ -182,7 +224,12 @@ func parseEd25519Key(req []byte) (*AddedKey, error) { return nil, err } priv := ed25519.PrivateKey(k.Priv) - return &AddedKey{PrivateKey: &priv, Comment: k.Comments}, nil + + addedKey := &AddedKey{PrivateKey: &priv, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil } func parseDSAKey(req []byte) (*AddedKey, error) { @@ -202,7 +249,11 @@ func parseDSAKey(req []byte) (*AddedKey, error) { X: k.X, } - return &AddedKey{PrivateKey: priv, Comment: k.Comments}, nil + addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil } func unmarshalECDSA(curveName string, keyBytes []byte, privScalar *big.Int) (priv *ecdsa.PrivateKey, err error) { @@ -243,7 +294,12 @@ func parseEd25519Cert(req []byte) (*AddedKey, error) { if !ok { return nil, errors.New("agent: bad ED25519 certificate") } - return &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}, nil + + addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil } func parseECDSAKey(req []byte) (*AddedKey, error) { @@ -257,7 +313,11 @@ func parseECDSAKey(req []byte) (*AddedKey, error) { return nil, err } - return &AddedKey{PrivateKey: priv, Comment: k.Comments}, nil + addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil } func parseRSACert(req []byte) (*AddedKey, error) { @@ -300,7 +360,11 @@ func parseRSACert(req []byte) (*AddedKey, error) { } priv.Precompute() - return &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}, nil + addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil } func parseDSACert(req []byte) (*AddedKey, error) { @@ -338,7 +402,11 @@ func parseDSACert(req []byte) (*AddedKey, error) { X: k.X, } - return &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}, nil + addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil } func parseECDSACert(req []byte) (*AddedKey, error) { @@ -371,7 +439,11 @@ func parseECDSACert(req []byte) (*AddedKey, error) { return nil, err } - return &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}, nil + addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments} + if err := setConstraints(addedKey, k.Constraints); err != nil { + return nil, err + } + return addedKey, nil } func (s *server) insertIdentity(req []byte) error { diff --git a/vendor/golang.org/x/crypto/ssh/agent/server_test.go b/vendor/golang.org/x/crypto/ssh/agent/server_test.go index 6b0837d94..038018ebb 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/server_test.go +++ b/vendor/golang.org/x/crypto/ssh/agent/server_test.go @@ -8,6 +8,9 @@ import ( "crypto" "crypto/rand" "fmt" + pseudorand "math/rand" + "reflect" + "strings" "testing" "golang.org/x/crypto/ssh" @@ -40,7 +43,7 @@ func TestSetupForwardAgent(t *testing.T) { defer a.Close() defer b.Close() - _, socket, cleanup := startAgent(t) + _, socket, cleanup := startOpenSSHAgent(t) defer cleanup() serverConf := ssh.ServerConfig{ @@ -207,3 +210,50 @@ func TestCertTypes(t *testing.T) { } } } + +func TestParseConstraints(t *testing.T) { + // Test LifetimeSecs + var msg = constrainLifetimeAgentMsg{pseudorand.Uint32()} + lifetimeSecs, _, _, err := parseConstraints(ssh.Marshal(msg)) + if err != nil { + t.Fatalf("parseConstraints: %v", err) + } + if lifetimeSecs != msg.LifetimeSecs { + t.Errorf("got lifetime %v, want %v", lifetimeSecs, msg.LifetimeSecs) + } + + // Test ConfirmBeforeUse + _, confirmBeforeUse, _, err := parseConstraints([]byte{agentConstrainConfirm}) + if err != nil { + t.Fatalf("%v", err) + } + if !confirmBeforeUse { + t.Error("got comfirmBeforeUse == false") + } + + // Test ConstraintExtensions + var data []byte + var expect []ConstraintExtension + for i := 0; i < 10; i++ { + var ext = ConstraintExtension{ + ExtensionName: fmt.Sprintf("name%d", i), + ExtensionDetails: []byte(fmt.Sprintf("details: %d", i)), + } + expect = append(expect, ext) + data = append(data, agentConstrainExtension) + data = append(data, ssh.Marshal(ext)...) + } + _, _, extensions, err := parseConstraints(data) + if err != nil { + t.Fatalf("%v", err) + } + if !reflect.DeepEqual(expect, extensions) { + t.Errorf("got extension %v, want %v", extensions, expect) + } + + // Test Unknown Constraint + _, _, _, err = parseConstraints([]byte{128}) + if err == nil || !strings.Contains(err.Error(), "unknown constraint") { + t.Errorf("unexpected error: %v", err) + } +} diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go index b6f4cc811..8a78b7ca0 100644 --- a/vendor/golang.org/x/crypto/ssh/server.go +++ b/vendor/golang.org/x/crypto/ssh/server.go @@ -67,7 +67,7 @@ type ServerConfig struct { PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error) // PublicKeyCallback, if non-nil, is called when a client - // offers a public key for authentication. It must return true + // offers a public key for authentication. It must return a nil error // if the given public key can be used to authenticate the // given user. For example, see CertChecker.Authenticate. A // call to this function does not guarantee that the key diff --git a/vendor/golang.org/x/crypto/ssh/session.go b/vendor/golang.org/x/crypto/ssh/session.go index 17e2aa85c..cc06e03f5 100644 --- a/vendor/golang.org/x/crypto/ssh/session.go +++ b/vendor/golang.org/x/crypto/ssh/session.go @@ -231,6 +231,26 @@ func (s *Session) RequestSubsystem(subsystem string) error { return err } +// RFC 4254 Section 6.7. +type ptyWindowChangeMsg struct { + Columns uint32 + Rows uint32 + Width uint32 + Height uint32 +} + +// WindowChange informs the remote host about a terminal window dimension change to h rows and w columns. +func (s *Session) WindowChange(h, w int) error { + req := ptyWindowChangeMsg{ + Columns: uint32(w), + Rows: uint32(h), + Width: uint32(w * 8), + Height: uint32(h * 8), + } + _, err := s.ch.SendRequest("window-change", false, Marshal(&req)) + return err +} + // RFC 4254 Section 6.9. type signalMsg struct { Signal string diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go b/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go index 9c1ffd145..cb23a5904 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go @@ -6,7 +6,7 @@ package terminal -import "syscall" +import "golang.org/x/sys/unix" -const ioctlReadTermios = syscall.TIOCGETA -const ioctlWriteTermios = syscall.TIOCSETA +const ioctlReadTermios = unix.TIOCGETA +const ioctlWriteTermios = unix.TIOCSETA diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go b/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go index 5883b22d7..5fadfe8a1 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go @@ -4,8 +4,7 @@ package terminal -// These constants are declared here, rather than importing -// them from the syscall package as some syscall packages, even -// on linux, for example gccgo, do not declare them. -const ioctlReadTermios = 0x5401 // syscall.TCGETS -const ioctlWriteTermios = 0x5402 // syscall.TCSETS +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TCGETS +const ioctlWriteTermios = unix.TCSETS diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go index e0a1f36ce..60979ccd0 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go @@ -17,53 +17,7 @@ package terminal import ( - "syscall" - "unsafe" -) - -const ( - enableLineInput = 2 - enableEchoInput = 4 - enableProcessedInput = 1 - enableWindowInput = 8 - enableMouseInput = 16 - enableInsertMode = 32 - enableQuickEditMode = 64 - enableExtendedFlags = 128 - enableAutoPosition = 256 - enableProcessedOutput = 1 - enableWrapAtEolOutput = 2 -) - -var kernel32 = syscall.NewLazyDLL("kernel32.dll") - -var ( - procGetConsoleMode = kernel32.NewProc("GetConsoleMode") - procSetConsoleMode = kernel32.NewProc("SetConsoleMode") - procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") -) - -type ( - short int16 - word uint16 - - coord struct { - x short - y short - } - smallRect struct { - left short - top short - right short - bottom short - } - consoleScreenBufferInfo struct { - size coord - cursorPosition coord - attributes word - window smallRect - maximumWindowSize coord - } + "golang.org/x/sys/windows" ) type State struct { @@ -73,8 +27,8 @@ type State struct { // IsTerminal returns true if the given file descriptor is a terminal. func IsTerminal(fd int) bool { var st uint32 - r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) - return r != 0 && e == 0 + err := windows.GetConsoleMode(windows.Handle(fd), &st) + return err == nil } // MakeRaw put the terminal connected to the given file descriptor into raw @@ -82,14 +36,12 @@ func IsTerminal(fd int) bool { // restored. func MakeRaw(fd int) (*State, error) { var st uint32 - _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) - if e != 0 { - return nil, error(e) + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err } - raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput) - _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0) - if e != 0 { - return nil, error(e) + raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) + if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil { + return nil, err } return &State{st}, nil } @@ -98,9 +50,8 @@ func MakeRaw(fd int) (*State, error) { // restore the terminal after a signal. func GetState(fd int) (*State, error) { var st uint32 - _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) - if e != 0 { - return nil, error(e) + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err } return &State{st}, nil } @@ -108,25 +59,23 @@ func GetState(fd int) (*State, error) { // Restore restores the terminal connected to the given file descriptor to a // previous state. func Restore(fd int, state *State) error { - _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0) - return err + return windows.SetConsoleMode(windows.Handle(fd), state.mode) } // GetSize returns the dimensions of the given terminal. func GetSize(fd int) (width, height int, err error) { - var info consoleScreenBufferInfo - _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0) - if e != 0 { - return 0, 0, error(e) + var info windows.ConsoleScreenBufferInfo + if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { + return 0, 0, err } - return int(info.size.x), int(info.size.y), nil + return int(info.Size.X), int(info.Size.Y), nil } // passwordReader is an io.Reader that reads from a specific Windows HANDLE. type passwordReader int func (r passwordReader) Read(buf []byte) (int, error) { - return syscall.Read(syscall.Handle(r), buf) + return windows.Read(windows.Handle(r), buf) } // ReadPassword reads a line of input from a terminal without local echo. This @@ -134,21 +83,19 @@ func (r passwordReader) Read(buf []byte) (int, error) { // returned does not include the \n. func ReadPassword(fd int) ([]byte, error) { var st uint32 - _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) - if e != 0 { - return nil, error(e) + if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { + return nil, err } old := st - st &^= (enableEchoInput) - st |= (enableProcessedInput | enableLineInput | enableProcessedOutput) - _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0) - if e != 0 { - return nil, error(e) + st &^= (windows.ENABLE_ECHO_INPUT) + st |= (windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) + if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil { + return nil, err } defer func() { - syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0) + windows.SetConsoleMode(windows.Handle(fd), old) }() return readPasswordLine(passwordReader(fd)) diff --git a/vendor/golang.org/x/crypto/ssh/test/session_test.go b/vendor/golang.org/x/crypto/ssh/test/session_test.go index fc7e4715b..8238d9d90 100644 --- a/vendor/golang.org/x/crypto/ssh/test/session_test.go +++ b/vendor/golang.org/x/crypto/ssh/test/session_test.go @@ -276,6 +276,54 @@ func TestValidTerminalMode(t *testing.T) { } } +func TestWindowChange(t *testing.T) { + server := newServer(t) + defer server.Shutdown() + conn := server.Dial(clientConfig()) + defer conn.Close() + + session, err := conn.NewSession() + if err != nil { + t.Fatalf("session failed: %v", err) + } + defer session.Close() + + stdout, err := session.StdoutPipe() + if err != nil { + t.Fatalf("unable to acquire stdout pipe: %s", err) + } + + stdin, err := session.StdinPipe() + if err != nil { + t.Fatalf("unable to acquire stdin pipe: %s", err) + } + + tm := ssh.TerminalModes{ssh.ECHO: 0} + if err = session.RequestPty("xterm", 80, 40, tm); err != nil { + t.Fatalf("req-pty failed: %s", err) + } + + if err := session.WindowChange(100, 100); err != nil { + t.Fatalf("window-change failed: %s", err) + } + + err = session.Shell() + if err != nil { + t.Fatalf("session failed: %s", err) + } + + stdin.Write([]byte("stty size && exit\n")) + + var buf bytes.Buffer + if _, err := io.Copy(&buf, stdout); err != nil { + t.Fatalf("reading failed: %s", err) + } + + if sttyOutput := buf.String(); !strings.Contains(sttyOutput, "100 100") { + t.Fatalf("terminal WindowChange failure: expected \"100 100\" stty output, got %s", sttyOutput) + } +} + func TestCiphers(t *testing.T) { var config ssh.Config config.SetDefaults() -- cgit v1.2.3-1-g7c22