// Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package ssh import ( "fmt" "net" ) // OpenChannelError is returned if the other side rejects an // OpenChannel request. type OpenChannelError struct { Reason RejectionReason Message string } func (e *OpenChannelError) Error() string { return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message) } // ConnMetadata holds metadata for the connection. type ConnMetadata interface { // User returns the user ID for this connection. User() string // SessionID returns the session hash, also denoted by H. SessionID() []byte // ClientVersion returns the client's version string as hashed // into the session ID. ClientVersion() []byte // ServerVersion returns the server's version string as hashed // into the session ID. ServerVersion() []byte // RemoteAddr returns the remote address for this connection. RemoteAddr() net.Addr // LocalAddr returns the local address for this connection. LocalAddr() net.Addr } // Conn represents an SSH connection for both server and client roles. // Conn is the basis for implementing an application layer, such // as ClientConn, which implements the traditional shell access for // clients. type Conn interface { ConnMetadata // SendRequest sends a global request, and returns the // reply. If wantReply is true, it returns the response status // and payload. See also RFC4254, section 4. SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) // OpenChannel tries to open an channel. If the request is // rejected, it returns *OpenChannelError. On success it returns // the SSH Channel and a Go channel for incoming, out-of-band // requests. The Go channel must be serviced, or the // connection will hang. OpenChannel(name string, data []byte) (Channel, <-chan *Request, error) // Close closes the underlying network connection Close() error // Wait blocks until the connection has shut down, and returns the // error causing the shutdown. Wait() error // TODO(hanwen): consider exposing: // RequestKeyChange // Disconnect } // DiscardRequests consumes and rejects all requests from the // passed-in channel. func DiscardRequests(in <-chan *Request) { for req := range in { if req.WantReply { req.Reply(false, nil) } } } // A connection represents an incoming connection. type connection struct { transport *handshakeTransport sshConn // The connection protocol. *mux } func (c *connection) Close() error { return c.sshConn.conn.Close() } // sshconn provides net.Conn metadata, but disallows direct reads and // writes. type sshConn struct { conn net.Conn user string sessionID []byte clientVersion []byte serverVersion []byte } func dup(src []byte) []byte { dst := make([]byte, len(src)) copy(dst, src) return dst } func (c *sshConn) User() string { return c.user } func (c *sshConn) RemoteAddr() net.Addr { return c.conn.RemoteAddr() } func (c *sshConn) Close() error { return c.conn.Close() } func (c *sshConn) LocalAddr() net.Addr { return c.conn.LocalAddr() } func (c *sshConn) SessionID() []byte { return dup(c.sessionID) } func (c *sshConn) ClientVersion() []byte { return dup(c.clientVersion) } func (c *sshConn) ServerVersion() []byte { return dup(c.serverVersion) }