1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ssh
6
7import (
8	"fmt"
9	"net"
10)
11
12// OpenChannelError is returned if the other side rejects an
13// OpenChannel request.
14type OpenChannelError struct {
15	Reason  RejectionReason
16	Message string
17}
18
19func (e *OpenChannelError) Error() string {
20	return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message)
21}
22
23// ConnMetadata holds metadata for the connection.
24type ConnMetadata interface {
25	// User returns the user ID for this connection.
26	User() string
27
28	// SessionID returns the session hash, also denoted by H.
29	SessionID() []byte
30
31	// ClientVersion returns the client's version string as hashed
32	// into the session ID.
33	ClientVersion() []byte
34
35	// ServerVersion returns the server's version string as hashed
36	// into the session ID.
37	ServerVersion() []byte
38
39	// RemoteAddr returns the remote address for this connection.
40	RemoteAddr() net.Addr
41
42	// LocalAddr returns the local address for this connection.
43	LocalAddr() net.Addr
44
45	// PartialSuccessMethods returns the ordered list of
46	// authentication methods that returned ErrPartialSuccess.
47	// It can be used inside callbacks to find if a multi-step
48	// authentication is done using the correct sequence and to
49	// return the authentication methods that can continue
50	PartialSuccessMethods() []string
51}
52
53// Conn represents an SSH connection for both server and client roles.
54// Conn is the basis for implementing an application layer, such
55// as ClientConn, which implements the traditional shell access for
56// clients.
57type Conn interface {
58	ConnMetadata
59
60	// SendRequest sends a global request, and returns the
61	// reply. If wantReply is true, it returns the response status
62	// and payload. See also RFC4254, section 4.
63	SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error)
64
65	// OpenChannel tries to open an channel. If the request is
66	// rejected, it returns *OpenChannelError. On success it returns
67	// the SSH Channel and a Go channel for incoming, out-of-band
68	// requests. The Go channel must be serviced, or the
69	// connection will hang.
70	OpenChannel(name string, data []byte) (Channel, <-chan *Request, error)
71
72	// Close closes the underlying network connection
73	Close() error
74
75	// Wait blocks until the connection has shut down, and returns the
76	// error causing the shutdown.
77	Wait() error
78
79	// TODO(hanwen): consider exposing:
80	//   RequestKeyChange
81	//   Disconnect
82}
83
84// DiscardRequests consumes and rejects all requests from the
85// passed-in channel.
86func DiscardRequests(in <-chan *Request) {
87	for req := range in {
88		if req.WantReply {
89			req.Reply(false, nil)
90		}
91	}
92}
93
94// A connection represents an incoming connection.
95type connection struct {
96	transport *handshakeTransport
97	sshConn
98
99	// The connection protocol.
100	*mux
101}
102
103func (c *connection) Close() error {
104	return c.sshConn.conn.Close()
105}
106
107// sshconn provides net.Conn metadata, but disallows direct reads and
108// writes.
109type sshConn struct {
110	conn net.Conn
111
112	user                  string
113	sessionID             []byte
114	clientVersion         []byte
115	serverVersion         []byte
116	partialSuccessMethods []string
117}
118
119func dup(src []byte) []byte {
120	dst := make([]byte, len(src))
121	copy(dst, src)
122	return dst
123}
124
125func (c *sshConn) PartialSuccessMethods() []string {
126	return c.partialSuccessMethods
127}
128
129func (c *sshConn) User() string {
130	return c.user
131}
132
133func (c *sshConn) RemoteAddr() net.Addr {
134	return c.conn.RemoteAddr()
135}
136
137func (c *sshConn) Close() error {
138	return c.conn.Close()
139}
140
141func (c *sshConn) LocalAddr() net.Addr {
142	return c.conn.LocalAddr()
143}
144
145func (c *sshConn) SessionID() []byte {
146	return dup(c.sessionID)
147}
148
149func (c *sshConn) ClientVersion() []byte {
150	return dup(c.clientVersion)
151}
152
153func (c *sshConn) ServerVersion() []byte {
154	return dup(c.serverVersion)
155}
156