github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/third_party/code.google.com/p/go.crypto/ssh/client.go (about) 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. 4 5 package ssh 6 7 import ( 8 "crypto" 9 "crypto/rand" 10 "errors" 11 "fmt" 12 "io" 13 "math/big" 14 "net" 15 "sync" 16 ) 17 18 // clientVersion is the fixed identification string that the client will use. 19 var clientVersion = []byte("SSH-2.0-Go\r\n") 20 21 // ClientConn represents the client side of an SSH connection. 22 type ClientConn struct { 23 *transport 24 config *ClientConfig 25 chanlist 26 } 27 28 // Client returns a new SSH client connection using c as the underlying transport. 29 func Client(c net.Conn, config *ClientConfig) (*ClientConn, error) { 30 conn := &ClientConn{ 31 transport: newTransport(c, config.rand()), 32 config: config, 33 } 34 if err := conn.handshake(); err != nil { 35 conn.Close() 36 return nil, err 37 } 38 go conn.mainLoop() 39 return conn, nil 40 } 41 42 // handshake performs the client side key exchange. See RFC 4253 Section 7. 43 func (c *ClientConn) handshake() error { 44 var magics handshakeMagics 45 46 if _, err := c.Write(clientVersion); err != nil { 47 return err 48 } 49 if err := c.Flush(); err != nil { 50 return err 51 } 52 magics.clientVersion = clientVersion[:len(clientVersion)-2] 53 54 // read remote server version 55 version, err := readVersion(c) 56 if err != nil { 57 return err 58 } 59 magics.serverVersion = version 60 clientKexInit := kexInitMsg{ 61 KexAlgos: supportedKexAlgos, 62 ServerHostKeyAlgos: supportedHostKeyAlgos, 63 CiphersClientServer: c.config.Crypto.ciphers(), 64 CiphersServerClient: c.config.Crypto.ciphers(), 65 MACsClientServer: supportedMACs, 66 MACsServerClient: supportedMACs, 67 CompressionClientServer: supportedCompressions, 68 CompressionServerClient: supportedCompressions, 69 } 70 kexInitPacket := marshal(msgKexInit, clientKexInit) 71 magics.clientKexInit = kexInitPacket 72 73 if err := c.writePacket(kexInitPacket); err != nil { 74 return err 75 } 76 packet, err := c.readPacket() 77 if err != nil { 78 return err 79 } 80 81 magics.serverKexInit = packet 82 83 var serverKexInit kexInitMsg 84 if err = unmarshal(&serverKexInit, packet, msgKexInit); err != nil { 85 return err 86 } 87 88 kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(c.transport, &clientKexInit, &serverKexInit) 89 if !ok { 90 return errors.New("ssh: no common algorithms") 91 } 92 93 if serverKexInit.FirstKexFollows && kexAlgo != serverKexInit.KexAlgos[0] { 94 // The server sent a Kex message for the wrong algorithm, 95 // which we have to ignore. 96 if _, err := c.readPacket(); err != nil { 97 return err 98 } 99 } 100 101 var H, K []byte 102 var hashFunc crypto.Hash 103 switch kexAlgo { 104 case kexAlgoDH14SHA1: 105 hashFunc = crypto.SHA1 106 dhGroup14Once.Do(initDHGroup14) 107 H, K, err = c.kexDH(dhGroup14, hashFunc, &magics, hostKeyAlgo) 108 default: 109 err = fmt.Errorf("ssh: unexpected key exchange algorithm %v", kexAlgo) 110 } 111 if err != nil { 112 return err 113 } 114 115 if err = c.writePacket([]byte{msgNewKeys}); err != nil { 116 return err 117 } 118 if err = c.transport.writer.setupKeys(clientKeys, K, H, H, hashFunc); err != nil { 119 return err 120 } 121 if packet, err = c.readPacket(); err != nil { 122 return err 123 } 124 if packet[0] != msgNewKeys { 125 return UnexpectedMessageError{msgNewKeys, packet[0]} 126 } 127 if err := c.transport.reader.setupKeys(serverKeys, K, H, H, hashFunc); err != nil { 128 return err 129 } 130 return c.authenticate(H) 131 } 132 133 // kexDH performs Diffie-Hellman key agreement on a ClientConn. The 134 // returned values are given the same names as in RFC 4253, section 8. 135 func (c *ClientConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handshakeMagics, hostKeyAlgo string) ([]byte, []byte, error) { 136 x, err := rand.Int(c.config.rand(), group.p) 137 if err != nil { 138 return nil, nil, err 139 } 140 X := new(big.Int).Exp(group.g, x, group.p) 141 kexDHInit := kexDHInitMsg{ 142 X: X, 143 } 144 if err := c.writePacket(marshal(msgKexDHInit, kexDHInit)); err != nil { 145 return nil, nil, err 146 } 147 148 packet, err := c.readPacket() 149 if err != nil { 150 return nil, nil, err 151 } 152 153 var kexDHReply = new(kexDHReplyMsg) 154 if err = unmarshal(kexDHReply, packet, msgKexDHReply); err != nil { 155 return nil, nil, err 156 } 157 158 if kexDHReply.Y.Sign() == 0 || kexDHReply.Y.Cmp(group.p) >= 0 { 159 return nil, nil, errors.New("server DH parameter out of bounds") 160 } 161 162 kInt := new(big.Int).Exp(kexDHReply.Y, x, group.p) 163 h := hashFunc.New() 164 writeString(h, magics.clientVersion) 165 writeString(h, magics.serverVersion) 166 writeString(h, magics.clientKexInit) 167 writeString(h, magics.serverKexInit) 168 writeString(h, kexDHReply.HostKey) 169 writeInt(h, X) 170 writeInt(h, kexDHReply.Y) 171 K := make([]byte, intLength(kInt)) 172 marshalInt(K, kInt) 173 h.Write(K) 174 175 H := h.Sum(nil) 176 177 return H, K, nil 178 } 179 180 // mainLoop reads incoming messages and routes channel messages 181 // to their respective ClientChans. 182 func (c *ClientConn) mainLoop() { 183 // TODO(dfc) signal the underlying close to all channels 184 defer c.Close() 185 for { 186 packet, err := c.readPacket() 187 if err != nil { 188 break 189 } 190 // TODO(dfc) A note on blocking channel use. 191 // The msg, win, data and dataExt channels of a clientChan can 192 // cause this loop to block indefinately if the consumer does 193 // not service them. 194 switch packet[0] { 195 case msgChannelData: 196 if len(packet) < 9 { 197 // malformed data packet 198 break 199 } 200 peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4]) 201 if length := int(packet[5])<<24 | int(packet[6])<<16 | int(packet[7])<<8 | int(packet[8]); length > 0 { 202 packet = packet[9:] 203 c.getChan(peersId).stdout.handleData(packet[:length]) 204 } 205 case msgChannelExtendedData: 206 if len(packet) < 13 { 207 // malformed data packet 208 break 209 } 210 peersId := uint32(packet[1])<<24 | uint32(packet[2])<<16 | uint32(packet[3])<<8 | uint32(packet[4]) 211 datatype := uint32(packet[5])<<24 | uint32(packet[6])<<16 | uint32(packet[7])<<8 | uint32(packet[8]) 212 if length := int(packet[9])<<24 | int(packet[10])<<16 | int(packet[11])<<8 | int(packet[12]); length > 0 { 213 packet = packet[13:] 214 // RFC 4254 5.2 defines data_type_code 1 to be data destined 215 // for stderr on interactive sessions. Other data types are 216 // silently discarded. 217 if datatype == 1 { 218 c.getChan(peersId).stderr.handleData(packet[:length]) 219 } 220 } 221 default: 222 switch msg := decode(packet).(type) { 223 case *channelOpenMsg: 224 c.getChan(msg.PeersId).msg <- msg 225 case *channelOpenConfirmMsg: 226 c.getChan(msg.PeersId).msg <- msg 227 case *channelOpenFailureMsg: 228 c.getChan(msg.PeersId).msg <- msg 229 case *channelCloseMsg: 230 ch := c.getChan(msg.PeersId) 231 ch.theyClosed = true 232 close(ch.stdin.win) 233 ch.stdout.eof() 234 ch.stderr.eof() 235 close(ch.msg) 236 if !ch.weClosed { 237 ch.weClosed = true 238 ch.sendClose() 239 } 240 c.chanlist.remove(msg.PeersId) 241 case *channelEOFMsg: 242 ch := c.getChan(msg.PeersId) 243 ch.stdout.eof() 244 // RFC 4254 is mute on how EOF affects dataExt messages but 245 // it is logical to signal EOF at the same time. 246 ch.stderr.eof() 247 case *channelRequestSuccessMsg: 248 c.getChan(msg.PeersId).msg <- msg 249 case *channelRequestFailureMsg: 250 c.getChan(msg.PeersId).msg <- msg 251 case *channelRequestMsg: 252 c.getChan(msg.PeersId).msg <- msg 253 case *windowAdjustMsg: 254 c.getChan(msg.PeersId).stdin.win <- int(msg.AdditionalBytes) 255 case *disconnectMsg: 256 break 257 default: 258 fmt.Printf("mainLoop: unhandled message %T: %v\n", msg, msg) 259 } 260 } 261 } 262 } 263 264 // Dial connects to the given network address using net.Dial and 265 // then initiates a SSH handshake, returning the resulting client connection. 266 func Dial(network, addr string, config *ClientConfig) (*ClientConn, error) { 267 conn, err := net.Dial(network, addr) 268 if err != nil { 269 return nil, err 270 } 271 return Client(conn, config) 272 } 273 274 // A ClientConfig structure is used to configure a ClientConn. After one has 275 // been passed to an SSH function it must not be modified. 276 type ClientConfig struct { 277 // Rand provides the source of entropy for key exchange. If Rand is 278 // nil, the cryptographic random reader in package crypto/rand will 279 // be used. 280 Rand io.Reader 281 282 // The username to authenticate. 283 User string 284 285 // A slice of ClientAuth methods. Only the first instance 286 // of a particular RFC 4252 method will be used during authentication. 287 Auth []ClientAuth 288 289 // Cryptographic-related configuration. 290 Crypto CryptoConfig 291 } 292 293 func (c *ClientConfig) rand() io.Reader { 294 if c.Rand == nil { 295 return rand.Reader 296 } 297 return c.Rand 298 } 299 300 // A clientChan represents a single RFC 4254 channel that is multiplexed 301 // over a single SSH connection. 302 type clientChan struct { 303 packetWriter 304 id, peersId uint32 305 stdin *chanWriter // receives window adjustments 306 stdout *chanReader // receives the payload of channelData messages 307 stderr *chanReader // receives the payload of channelExtendedData messages 308 msg chan interface{} // incoming messages 309 theyClosed bool // indicates the close msg has been received from the remote side 310 weClosed bool // incidates the close msg has been sent from our side 311 } 312 313 // newClientChan returns a partially constructed *clientChan 314 // using the local id provided. To be usable clientChan.peersId 315 // needs to be assigned once known. 316 func newClientChan(t *transport, id uint32) *clientChan { 317 c := &clientChan{ 318 packetWriter: t, 319 id: id, 320 msg: make(chan interface{}, 16), 321 } 322 c.stdin = &chanWriter{ 323 win: make(chan int, 16), 324 clientChan: c, 325 } 326 c.stdout = &chanReader{ 327 data: make(chan []byte, 16), 328 clientChan: c, 329 } 330 c.stderr = &chanReader{ 331 data: make(chan []byte, 16), 332 clientChan: c, 333 } 334 return c 335 } 336 337 // waitForChannelOpenResponse, if successful, fills out 338 // the peerId and records any initial window advertisement. 339 func (c *clientChan) waitForChannelOpenResponse() error { 340 switch msg := (<-c.msg).(type) { 341 case *channelOpenConfirmMsg: 342 // fixup peersId field 343 c.peersId = msg.MyId 344 c.stdin.win <- int(msg.MyWindow) 345 return nil 346 case *channelOpenFailureMsg: 347 return errors.New(safeString(msg.Message)) 348 } 349 return errors.New("unexpected packet") 350 } 351 352 // sendEOF sends EOF to the server. RFC 4254 Section 5.3 353 func (c *clientChan) sendEOF() error { 354 return c.writePacket(marshal(msgChannelEOF, channelEOFMsg{ 355 PeersId: c.peersId, 356 })) 357 } 358 359 // sendClose signals the intent to close the channel. 360 func (c *clientChan) sendClose() error { 361 return c.writePacket(marshal(msgChannelClose, channelCloseMsg{ 362 PeersId: c.peersId, 363 })) 364 } 365 366 // Close closes the channel. This does not close the underlying connection. 367 func (c *clientChan) Close() error { 368 if !c.weClosed { 369 c.weClosed = true 370 return c.sendClose() 371 } 372 return nil 373 } 374 375 // Thread safe channel list. 376 type chanlist struct { 377 // protects concurrent access to chans 378 sync.Mutex 379 // chans are indexed by the local id of the channel, clientChan.id. 380 // The PeersId value of messages received by ClientConn.mainLoop is 381 // used to locate the right local clientChan in this slice. 382 chans []*clientChan 383 } 384 385 // Allocate a new ClientChan with the next avail local id. 386 func (c *chanlist) newChan(t *transport) *clientChan { 387 c.Lock() 388 defer c.Unlock() 389 for i := range c.chans { 390 if c.chans[i] == nil { 391 ch := newClientChan(t, uint32(i)) 392 c.chans[i] = ch 393 return ch 394 } 395 } 396 i := len(c.chans) 397 ch := newClientChan(t, uint32(i)) 398 c.chans = append(c.chans, ch) 399 return ch 400 } 401 402 func (c *chanlist) getChan(id uint32) *clientChan { 403 c.Lock() 404 defer c.Unlock() 405 return c.chans[int(id)] 406 } 407 408 func (c *chanlist) remove(id uint32) { 409 c.Lock() 410 defer c.Unlock() 411 c.chans[int(id)] = nil 412 } 413 414 // A chanWriter represents the stdin of a remote process. 415 type chanWriter struct { 416 win chan int // receives window adjustments 417 rwin int // current rwin size 418 clientChan *clientChan // the channel backing this writer 419 } 420 421 // Write writes data to the remote process's standard input. 422 func (w *chanWriter) Write(data []byte) (written int, err error) { 423 for len(data) > 0 { 424 for w.rwin < 1 { 425 win, ok := <-w.win 426 if !ok { 427 return 0, io.EOF 428 } 429 w.rwin += win 430 } 431 n := min(len(data), w.rwin) 432 peersId := w.clientChan.peersId 433 packet := []byte{ 434 msgChannelData, 435 byte(peersId >> 24), byte(peersId >> 16), byte(peersId >> 8), byte(peersId), 436 byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n), 437 } 438 if err = w.clientChan.writePacket(append(packet, data[:n]...)); err != nil { 439 break 440 } 441 data = data[n:] 442 w.rwin -= n 443 written += n 444 } 445 return 446 } 447 448 func min(a, b int) int { 449 if a < b { 450 return a 451 } 452 return b 453 } 454 455 func (w *chanWriter) Close() error { 456 return w.clientChan.sendEOF() 457 } 458 459 // A chanReader represents stdout or stderr of a remote process. 460 type chanReader struct { 461 // TODO(dfc) a fixed size channel may not be the right data structure. 462 // If writes to this channel block, they will block mainLoop, making 463 // it unable to receive new messages from the remote side. 464 data chan []byte // receives data from remote 465 dataClosed bool // protects data from being closed twice 466 clientChan *clientChan // the channel backing this reader 467 buf []byte 468 } 469 470 // eof signals to the consumer that there is no more data to be received. 471 func (r *chanReader) eof() { 472 if !r.dataClosed { 473 r.dataClosed = true 474 close(r.data) 475 } 476 } 477 478 // handleData sends buf to the reader's consumer. If r.data is closed 479 // the data will be silently discarded 480 func (r *chanReader) handleData(buf []byte) { 481 if !r.dataClosed { 482 r.data <- buf 483 } 484 } 485 486 // Read reads data from the remote process's stdout or stderr. 487 func (r *chanReader) Read(data []byte) (int, error) { 488 var ok bool 489 for { 490 if len(r.buf) > 0 { 491 n := copy(data, r.buf) 492 r.buf = r.buf[n:] 493 msg := windowAdjustMsg{ 494 PeersId: r.clientChan.peersId, 495 AdditionalBytes: uint32(n), 496 } 497 return n, r.clientChan.writePacket(marshal(msgChannelWindowAdjust, msg)) 498 } 499 r.buf, ok = <-r.data 500 if !ok { 501 return 0, io.EOF 502 } 503 } 504 panic("unreachable") 505 }