1 // Copyright 2011 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.
18 // clientVersion is the fixed identification string that the client will use.
19 var clientVersion = []byte("SSH-2.0-Go\r\n")
21 // ClientConn represents the client side of an SSH connection.
22 type ClientConn struct {
28 // Client returns a new SSH client connection using c as the underlying transport.
29 func Client(c net.Conn, config *ClientConfig) (*ClientConn, os.Error) {
31 transport: newTransport(c, config.rand()),
34 if err := conn.handshake(); err != nil {
38 if err := conn.authenticate(); err != nil {
46 // handshake performs the client side key exchange. See RFC 4253 Section 7.
47 func (c *ClientConn) handshake() os.Error {
48 var magics handshakeMagics
50 if _, err := c.Write(clientVersion); err != nil {
53 if err := c.Flush(); err != nil {
56 magics.clientVersion = clientVersion[:len(clientVersion)-2]
58 // read remote server version
59 version, err := readVersion(c)
63 magics.serverVersion = version
64 clientKexInit := kexInitMsg{
65 KexAlgos: supportedKexAlgos,
66 ServerHostKeyAlgos: supportedHostKeyAlgos,
67 CiphersClientServer: supportedCiphers,
68 CiphersServerClient: supportedCiphers,
69 MACsClientServer: supportedMACs,
70 MACsServerClient: supportedMACs,
71 CompressionClientServer: supportedCompressions,
72 CompressionServerClient: supportedCompressions,
74 kexInitPacket := marshal(msgKexInit, clientKexInit)
75 magics.clientKexInit = kexInitPacket
77 if err := c.writePacket(kexInitPacket); err != nil {
80 packet, err := c.readPacket()
85 magics.serverKexInit = packet
87 var serverKexInit kexInitMsg
88 if err = unmarshal(&serverKexInit, packet, msgKexInit); err != nil {
92 kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(c.transport, &clientKexInit, &serverKexInit)
94 return os.NewError("ssh: no common algorithms")
97 if serverKexInit.FirstKexFollows && kexAlgo != serverKexInit.KexAlgos[0] {
98 // The server sent a Kex message for the wrong algorithm,
99 // which we have to ignore.
100 if _, err := c.readPacket(); err != nil {
106 var hashFunc crypto.Hash
108 case kexAlgoDH14SHA1:
109 hashFunc = crypto.SHA1
110 dhGroup14Once.Do(initDHGroup14)
111 H, K, err = c.kexDH(dhGroup14, hashFunc, &magics, hostKeyAlgo)
113 err = fmt.Errorf("ssh: unexpected key exchange algorithm %v", kexAlgo)
119 if err = c.writePacket([]byte{msgNewKeys}); err != nil {
122 if err = c.transport.writer.setupKeys(clientKeys, K, H, H, hashFunc); err != nil {
125 if packet, err = c.readPacket(); err != nil {
128 if packet[0] != msgNewKeys {
129 return UnexpectedMessageError{msgNewKeys, packet[0]}
131 return c.transport.reader.setupKeys(serverKeys, K, H, H, hashFunc)
134 // authenticate authenticates with the remote server. See RFC 4252.
135 // Only "password" authentication is supported.
136 func (c *ClientConn) authenticate() os.Error {
137 if err := c.writePacket(marshal(msgServiceRequest, serviceRequestMsg{serviceUserAuth})); err != nil {
140 packet, err := c.readPacket()
145 var serviceAccept serviceAcceptMsg
146 if err = unmarshal(&serviceAccept, packet, msgServiceAccept); err != nil {
150 // TODO(dfc) support proper authentication method negotation
152 if c.config.Password != "" {
155 if err := c.sendUserAuthReq(method); err != nil {
159 if packet, err = c.readPacket(); err != nil {
163 if packet[0] != msgUserAuthSuccess {
164 return UnexpectedMessageError{msgUserAuthSuccess, packet[0]}
169 func (c *ClientConn) sendUserAuthReq(method string) os.Error {
170 length := stringLength([]byte(c.config.Password)) + 1
171 payload := make([]byte, length)
172 // always false for password auth, see RFC 4252 Section 8.
174 marshalString(payload[1:], []byte(c.config.Password))
176 return c.writePacket(marshal(msgUserAuthRequest, userAuthRequestMsg{
184 // kexDH performs Diffie-Hellman key agreement on a ClientConn. The
185 // returned values are given the same names as in RFC 4253, section 8.
186 func (c *ClientConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handshakeMagics, hostKeyAlgo string) ([]byte, []byte, os.Error) {
187 x, err := rand.Int(c.config.rand(), group.p)
191 X := new(big.Int).Exp(group.g, x, group.p)
192 kexDHInit := kexDHInitMsg{
195 if err := c.writePacket(marshal(msgKexDHInit, kexDHInit)); err != nil {
199 packet, err := c.readPacket()
204 var kexDHReply = new(kexDHReplyMsg)
205 if err = unmarshal(kexDHReply, packet, msgKexDHReply); err != nil {
209 if kexDHReply.Y.Sign() == 0 || kexDHReply.Y.Cmp(group.p) >= 0 {
210 return nil, nil, os.NewError("server DH parameter out of bounds")
213 kInt := new(big.Int).Exp(kexDHReply.Y, x, group.p)
215 writeString(h, magics.clientVersion)
216 writeString(h, magics.serverVersion)
217 writeString(h, magics.clientKexInit)
218 writeString(h, magics.serverKexInit)
219 writeString(h, kexDHReply.HostKey)
221 writeInt(h, kexDHReply.Y)
222 K := make([]byte, intLength(kInt))
231 // openChan opens a new client channel. The most common session type is "session".
232 // The full set of valid session types are listed in RFC 4250 4.9.1.
233 func (c *ClientConn) openChan(typ string) (*clientChan, os.Error) {
234 ch := c.newChan(c.transport)
235 if err := c.writePacket(marshal(msgChannelOpen, channelOpenMsg{
238 PeersWindow: 1 << 14,
239 MaxPacketSize: 1 << 15, // RFC 4253 6.1
241 c.chanlist.remove(ch.id)
245 switch msg := (<-ch.msg).(type) {
246 case *channelOpenConfirmMsg:
247 ch.peersId = msg.MyId
248 case *channelOpenFailureMsg:
249 c.chanlist.remove(ch.id)
250 return nil, os.NewError(msg.Message)
252 c.chanlist.remove(ch.id)
253 return nil, os.NewError("Unexpected packet")
258 // mainloop reads incoming messages and routes channel messages
259 // to their respective ClientChans.
260 func (c *ClientConn) mainLoop() {
261 // TODO(dfc) signal the underlying close to all channels
264 packet, err := c.readPacket()
268 // TODO(dfc) A note on blocking channel use.
269 // The msg, win, data and dataExt channels of a clientChan can
270 // cause this loop to block indefinately if the consumer does
275 // malformed data packet
278 peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4])
279 if length := int(packet[5])<<24 | int(packet[6])<<16 | int(packet[7])<<8 | int(packet[8]); length > 0 {
281 c.getChan(peersId).data <- packet[:length]
283 case msgChannelExtendedData:
284 if len(packet) < 13 {
285 // malformed data packet
288 peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4])
289 datatype := uint32(packet[5])<<24 | uint32(packet[6])<<16 | uint32(packet[7])<<8 | uint32(packet[8])
290 if length := int(packet[9])<<24 | int(packet[10])<<16 | int(packet[11])<<8 | int(packet[12]); length > 0 {
292 // RFC 4254 5.2 defines data_type_code 1 to be data destined
293 // for stderr on interactive sessions. Other data types are
294 // silently discarded.
296 c.getChan(peersId).dataExt <- packet[:length]
300 switch msg := decode(packet).(type) {
301 case *channelOpenMsg:
302 c.getChan(msg.PeersId).msg <- msg
303 case *channelOpenConfirmMsg:
304 c.getChan(msg.PeersId).msg <- msg
305 case *channelOpenFailureMsg:
306 c.getChan(msg.PeersId).msg <- msg
307 case *channelCloseMsg:
308 ch := c.getChan(msg.PeersId)
312 c.chanlist.remove(msg.PeersId)
314 c.getChan(msg.PeersId).msg <- msg
315 case *channelRequestSuccessMsg:
316 c.getChan(msg.PeersId).msg <- msg
317 case *channelRequestFailureMsg:
318 c.getChan(msg.PeersId).msg <- msg
319 case *channelRequestMsg:
320 c.getChan(msg.PeersId).msg <- msg
321 case *windowAdjustMsg:
322 c.getChan(msg.PeersId).win <- int(msg.AdditionalBytes)
324 fmt.Printf("mainLoop: unhandled %#v\n", msg)
330 // Dial connects to the given network address using net.Dial and
331 // then initiates a SSH handshake, returning the resulting client connection.
332 func Dial(network, addr string, config *ClientConfig) (*ClientConn, os.Error) {
333 conn, err := net.Dial(network, addr)
337 return Client(conn, config)
340 // A ClientConfig structure is used to configure a ClientConn. After one has
341 // been passed to an SSH function it must not be modified.
342 type ClientConfig struct {
343 // Rand provides the source of entropy for key exchange. If Rand is
344 // nil, the cryptographic random reader in package crypto/rand will
348 // The username to authenticate.
351 // Used for "password" method authentication.
355 func (c *ClientConfig) rand() io.Reader {
362 // A clientChan represents a single RFC 4254 channel that is multiplexed
363 // over a single SSH connection.
364 type clientChan struct {
367 data chan []byte // receives the payload of channelData messages
368 dataExt chan []byte // receives the payload of channelExtendedData messages
369 win chan int // receives window adjustments
370 msg chan interface{} // incoming messages
373 func newClientChan(t *transport, id uint32) *clientChan {
377 data: make(chan []byte, 16),
378 dataExt: make(chan []byte, 16),
379 win: make(chan int, 16),
380 msg: make(chan interface{}, 16),
384 // Close closes the channel. This does not close the underlying connection.
385 func (c *clientChan) Close() os.Error {
386 return c.writePacket(marshal(msgChannelClose, channelCloseMsg{
391 func (c *clientChan) sendChanReq(req channelRequestMsg) os.Error {
392 if err := c.writePacket(marshal(msgChannelRequest, req)); err != nil {
396 if _, ok := msg.(*channelRequestSuccessMsg); ok {
399 return fmt.Errorf("failed to complete request: %s, %#v", req.Request, msg)
402 // Thread safe channel list.
403 type chanlist struct {
404 // protects concurrent access to chans
406 // chans are indexed by the local id of the channel, clientChan.id.
407 // The PeersId value of messages received by ClientConn.mainloop is
408 // used to locate the right local clientChan in this slice.
412 // Allocate a new ClientChan with the next avail local id.
413 func (c *chanlist) newChan(t *transport) *clientChan {
416 for i := range c.chans {
417 if c.chans[i] == nil {
418 ch := newClientChan(t, uint32(i))
424 ch := newClientChan(t, uint32(i))
425 c.chans = append(c.chans, ch)
429 func (c *chanlist) getChan(id uint32) *clientChan {
432 return c.chans[int(id)]
435 func (c *chanlist) remove(id uint32) {
438 c.chans[int(id)] = nil
441 // A chanWriter represents the stdin of a remote process.
442 type chanWriter struct {
443 win chan int // receives window adjustments
444 id uint32 // this channel's id
445 rwin int // current rwin size
446 packetWriter // for sending channelDataMsg
449 // Write writes data to the remote process's standard input.
450 func (w *chanWriter) Write(data []byte) (n int, err os.Error) {
461 packet := make([]byte, 0, 9+n)
462 packet = append(packet, msgChannelData,
463 byte(w.id)>>24, byte(w.id)>>16, byte(w.id)>>8, byte(w.id),
464 byte(n)>>24, byte(n)>>16, byte(n)>>8, byte(n))
465 err = w.writePacket(append(packet, data...))
472 func (w *chanWriter) Close() os.Error {
473 return w.writePacket(marshal(msgChannelEOF, channelEOFMsg{w.id}))
476 // A chanReader represents stdout or stderr of a remote process.
477 type chanReader struct {
478 // TODO(dfc) a fixed size channel may not be the right data structure.
479 // If writes to this channel block, they will block mainLoop, making
480 // it unable to receive new messages from the remote side.
481 data chan []byte // receives data from remote
483 packetWriter // for sending windowAdjustMsg
487 // Read reads data from the remote process's stdout or stderr.
488 func (r *chanReader) Read(data []byte) (int, os.Error) {
492 n := copy(data, r.buf)
494 msg := windowAdjustMsg{
496 AdditionalBytes: uint32(n),
498 return n, r.writePacket(marshal(msgChannelWindowAdjust, msg))
508 func (r *chanReader) Close() os.Error {
509 return r.writePacket(marshal(msgChannelEOF, channelEOFMsg{r.id}))