github.com/inflatablewoman/deis@v1.0.1-0.20141111034523-a4511c46a6ce/deisctl/Godeps/_workspace/src/code.google.com/p/go.crypto/ssh/channel.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 "encoding/binary" 9 "errors" 10 "fmt" 11 "io" 12 "log" 13 "sync" 14 ) 15 16 const ( 17 minPacketLength = 9 18 // channelMaxPacket contains the maximum number of bytes that will be 19 // sent in a single packet. As per RFC 4253, section 6.1, 32k is also 20 // the minimum. 21 channelMaxPacket = 1 << 15 22 // We follow OpenSSH here. 23 channelWindowSize = 64 * channelMaxPacket 24 ) 25 26 // NewChannel represents an incoming request to a channel. It must either be 27 // accepted for use by calling Accept, or rejected by calling Reject. 28 type NewChannel interface { 29 // Accept accepts the channel creation request. It returns the Channel 30 // and a Go channel containing SSH requests. The Go channel must be 31 // serviced otherwise the Channel will hang. 32 Accept() (Channel, <-chan *Request, error) 33 34 // Reject rejects the channel creation request. After calling 35 // this, no other methods on the Channel may be called. 36 Reject(reason RejectionReason, message string) error 37 38 // ChannelType returns the type of the channel, as supplied by the 39 // client. 40 ChannelType() string 41 42 // ExtraData returns the arbitrary payload for this channel, as supplied 43 // by the client. This data is specific to the channel type. 44 ExtraData() []byte 45 } 46 47 // A Channel is an ordered, reliable, flow-controlled, duplex stream 48 // that is multiplexed over an SSH connection. 49 type Channel interface { 50 // Read reads up to len(data) bytes from the channel. 51 Read(data []byte) (int, error) 52 53 // Write writes len(data) bytes to the channel. 54 Write(data []byte) (int, error) 55 56 // Close signals end of channel use. No data may be sent after this 57 // call. 58 Close() error 59 60 // CloseWrite signals the end of sending in-band 61 // data. Requests may still be sent, and the other side may 62 // still send data 63 CloseWrite() error 64 65 // SendRequest sends a channel request. If wantReply is true, 66 // it will wait for a reply and return the result as a 67 // boolean, otherwise the return value will be false. Channel 68 // requests are out-of-band messages so they may be sent even 69 // if the data stream is closed or blocked by flow control. 70 SendRequest(name string, wantReply bool, payload []byte) (bool, error) 71 72 // Stderr returns an io.ReadWriter that writes to this channel with the 73 // extended data type set to stderr. 74 Stderr() io.ReadWriter 75 } 76 77 // Request is a request sent outside of the normal stream of 78 // data. Requests can either be specific to an SSH channel, or they 79 // can be global. 80 type Request struct { 81 Type string 82 WantReply bool 83 Payload []byte 84 85 ch *channel 86 mux *mux 87 } 88 89 // Reply sends a response to a request. It must be called for all requests 90 // where WantReply is true and is a no-op otherwise. The payload argument is 91 // ignored for replies to channel-specific requests. 92 func (r *Request) Reply(ok bool, payload []byte) error { 93 if !r.WantReply { 94 return nil 95 } 96 97 if r.ch == nil { 98 return r.mux.ackRequest(ok, payload) 99 } 100 101 return r.ch.ackRequest(ok) 102 } 103 104 // RejectionReason is an enumeration used when rejecting channel creation 105 // requests. See RFC 4254, section 5.1. 106 type RejectionReason uint32 107 108 const ( 109 Prohibited RejectionReason = iota + 1 110 ConnectionFailed 111 UnknownChannelType 112 ResourceShortage 113 ) 114 115 // String converts the rejection reason to human readable form. 116 func (r RejectionReason) String() string { 117 switch r { 118 case Prohibited: 119 return "administratively prohibited" 120 case ConnectionFailed: 121 return "connect failed" 122 case UnknownChannelType: 123 return "unknown channel type" 124 case ResourceShortage: 125 return "resource shortage" 126 } 127 return fmt.Sprintf("unknown reason %d", int(r)) 128 } 129 130 func min(a uint32, b int) uint32 { 131 if a < uint32(b) { 132 return a 133 } 134 return uint32(b) 135 } 136 137 type channelDirection uint8 138 139 const ( 140 channelInbound channelDirection = iota 141 channelOutbound 142 ) 143 144 // channel is an implementation of the Channel interface that works 145 // with the mux class. 146 type channel struct { 147 // R/O after creation 148 chanType string 149 extraData []byte 150 localId, remoteId uint32 151 152 // maxIncomingPayload and maxRemotePayload are the maximum 153 // payload sizes of normal and extended data packets for 154 // receiving and sending, respectively. The wire packet will 155 // be 9 or 13 bytes larger (excluding encryption overhead). 156 maxIncomingPayload uint32 157 maxRemotePayload uint32 158 159 mux *mux 160 161 // decided is set to true if an accept or reject message has been sent 162 // (for outbound channels) or received (for inbound channels). 163 decided bool 164 165 // direction contains either channelOutbound, for channels created 166 // locally, or channelInbound, for channels created by the peer. 167 direction channelDirection 168 169 // Pending internal channel messages. 170 msg chan interface{} 171 172 // Since requests have no ID, there can be only one request 173 // with WantReply=true outstanding. This lock is held by a 174 // goroutine that has such an outgoing request pending. 175 sentRequestMu sync.Mutex 176 177 incomingRequests chan *Request 178 179 sentEOF bool 180 181 // thread-safe data 182 remoteWin window 183 pending *buffer 184 extPending *buffer 185 186 // windowMu protects myWindow, the flow-control window. 187 windowMu sync.Mutex 188 myWindow uint32 189 190 // writeMu serializes calls to mux.conn.writePacket() and 191 // protects sentClose. This mutex must be different from 192 // windowMu, as writePacket can block if there is a key 193 // exchange pending 194 writeMu sync.Mutex 195 sentClose bool 196 } 197 198 // writePacket sends a packet. If the packet is a channel close, it updates 199 // sentClose. This method takes the lock c.writeMu. 200 func (c *channel) writePacket(packet []byte) error { 201 c.writeMu.Lock() 202 if c.sentClose { 203 c.writeMu.Unlock() 204 return io.EOF 205 } 206 c.sentClose = (packet[0] == msgChannelClose) 207 err := c.mux.conn.writePacket(packet) 208 c.writeMu.Unlock() 209 return err 210 } 211 212 func (c *channel) sendMessage(msg interface{}) error { 213 if debugMux { 214 log.Printf("send %d: %#v", c.mux.chanList.offset, msg) 215 } 216 217 p := Marshal(msg) 218 binary.BigEndian.PutUint32(p[1:], c.remoteId) 219 return c.writePacket(p) 220 } 221 222 // WriteExtended writes data to a specific extended stream. These streams are 223 // used, for example, for stderr. 224 func (c *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) { 225 if c.sentEOF { 226 return 0, io.EOF 227 } 228 // 1 byte message type, 4 bytes remoteId, 4 bytes data length 229 opCode := byte(msgChannelData) 230 headerLength := uint32(9) 231 if extendedCode > 0 { 232 headerLength += 4 233 opCode = msgChannelExtendedData 234 } 235 236 for len(data) > 0 { 237 space := min(c.maxRemotePayload, len(data)) 238 if space, err = c.remoteWin.reserve(space); err != nil { 239 return n, err 240 } 241 todo := data[:space] 242 243 packet := make([]byte, headerLength+uint32(len(todo))) 244 packet[0] = opCode 245 binary.BigEndian.PutUint32(packet[1:], c.remoteId) 246 if extendedCode > 0 { 247 binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode)) 248 } 249 binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo))) 250 copy(packet[headerLength:], todo) 251 if err = c.writePacket(packet); err != nil { 252 return n, err 253 } 254 255 n += len(todo) 256 data = data[len(todo):] 257 } 258 259 return n, err 260 } 261 262 func (c *channel) handleData(packet []byte) error { 263 headerLen := 9 264 isExtendedData := packet[0] == msgChannelExtendedData 265 if isExtendedData { 266 headerLen = 13 267 } 268 if len(packet) < headerLen { 269 // malformed data packet 270 return parseError(packet[0]) 271 } 272 273 var extended uint32 274 if isExtendedData { 275 extended = binary.BigEndian.Uint32(packet[5:]) 276 } 277 278 length := binary.BigEndian.Uint32(packet[headerLen-4 : headerLen]) 279 if length == 0 { 280 return nil 281 } 282 if length > c.maxIncomingPayload { 283 // TODO(hanwen): should send Disconnect? 284 return errors.New("ssh: incoming packet exceeds maximum payload size") 285 } 286 287 data := packet[headerLen:] 288 if length != uint32(len(data)) { 289 return errors.New("ssh: wrong packet length") 290 } 291 292 c.windowMu.Lock() 293 if c.myWindow < length { 294 c.windowMu.Unlock() 295 // TODO(hanwen): should send Disconnect with reason? 296 return errors.New("ssh: remote side wrote too much") 297 } 298 c.myWindow -= length 299 c.windowMu.Unlock() 300 301 if extended == 1 { 302 c.extPending.write(data) 303 } else if extended > 0 { 304 // discard other extended data. 305 } else { 306 c.pending.write(data) 307 } 308 return nil 309 } 310 311 func (c *channel) adjustWindow(n uint32) error { 312 c.windowMu.Lock() 313 // Since myWindow is managed on our side, and can never exceed 314 // the initial window setting, we don't worry about overflow. 315 c.myWindow += uint32(n) 316 c.windowMu.Unlock() 317 return c.sendMessage(windowAdjustMsg{ 318 AdditionalBytes: uint32(n), 319 }) 320 } 321 322 func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) { 323 switch extended { 324 case 1: 325 n, err = c.extPending.Read(data) 326 case 0: 327 n, err = c.pending.Read(data) 328 default: 329 return 0, fmt.Errorf("ssh: extended code %d unimplemented", extended) 330 } 331 332 if n > 0 { 333 err = c.adjustWindow(uint32(n)) 334 // sendWindowAdjust can return io.EOF if the remote 335 // peer has closed the connection, however we want to 336 // defer forwarding io.EOF to the caller of Read until 337 // the buffer has been drained. 338 if n > 0 && err == io.EOF { 339 err = nil 340 } 341 } 342 343 return n, err 344 } 345 346 func (c *channel) close() { 347 c.pending.eof() 348 c.extPending.eof() 349 close(c.msg) 350 close(c.incomingRequests) 351 c.writeMu.Lock() 352 // This is not necesary for a normal channel teardown, but if 353 // there was another error, it is. 354 c.sentClose = true 355 c.writeMu.Unlock() 356 // Unblock writers. 357 c.remoteWin.close() 358 } 359 360 // responseMessageReceived is called when a success or failure message is 361 // received on a channel to check that such a message is reasonable for the 362 // given channel. 363 func (c *channel) responseMessageReceived() error { 364 if c.direction == channelInbound { 365 return errors.New("ssh: channel response message received on inbound channel") 366 } 367 if c.decided { 368 return errors.New("ssh: duplicate response received for channel") 369 } 370 c.decided = true 371 return nil 372 } 373 374 func (c *channel) handlePacket(packet []byte) error { 375 switch packet[0] { 376 case msgChannelData, msgChannelExtendedData: 377 return c.handleData(packet) 378 case msgChannelClose: 379 c.sendMessage(channelCloseMsg{PeersId: c.remoteId}) 380 c.mux.chanList.remove(c.localId) 381 c.close() 382 return nil 383 case msgChannelEOF: 384 // RFC 4254 is mute on how EOF affects dataExt messages but 385 // it is logical to signal EOF at the same time. 386 c.extPending.eof() 387 c.pending.eof() 388 return nil 389 } 390 391 decoded, err := decode(packet) 392 if err != nil { 393 return err 394 } 395 396 switch msg := decoded.(type) { 397 case *channelOpenFailureMsg: 398 if err := c.responseMessageReceived(); err != nil { 399 return err 400 } 401 c.mux.chanList.remove(msg.PeersId) 402 c.msg <- msg 403 case *channelOpenConfirmMsg: 404 if err := c.responseMessageReceived(); err != nil { 405 return err 406 } 407 if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { 408 return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize) 409 } 410 c.remoteId = msg.MyId 411 c.maxRemotePayload = msg.MaxPacketSize 412 c.remoteWin.add(msg.MyWindow) 413 c.msg <- msg 414 case *windowAdjustMsg: 415 if !c.remoteWin.add(msg.AdditionalBytes) { 416 return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes) 417 } 418 case *channelRequestMsg: 419 req := Request{ 420 Type: msg.Request, 421 WantReply: msg.WantReply, 422 Payload: msg.RequestSpecificData, 423 ch: c, 424 } 425 426 c.incomingRequests <- &req 427 default: 428 c.msg <- msg 429 } 430 return nil 431 } 432 433 func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel { 434 ch := &channel{ 435 remoteWin: window{Cond: newCond()}, 436 myWindow: channelWindowSize, 437 pending: newBuffer(), 438 extPending: newBuffer(), 439 direction: direction, 440 incomingRequests: make(chan *Request, 16), 441 msg: make(chan interface{}, 16), 442 chanType: chanType, 443 extraData: extraData, 444 mux: m, 445 } 446 ch.localId = m.chanList.add(ch) 447 return ch 448 } 449 450 var errUndecided = errors.New("ssh: must Accept or Reject channel") 451 var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once") 452 453 type extChannel struct { 454 code uint32 455 ch *channel 456 } 457 458 func (e *extChannel) Write(data []byte) (n int, err error) { 459 return e.ch.WriteExtended(data, e.code) 460 } 461 462 func (e *extChannel) Read(data []byte) (n int, err error) { 463 return e.ch.ReadExtended(data, e.code) 464 } 465 466 func (c *channel) Accept() (Channel, <-chan *Request, error) { 467 if c.decided { 468 return nil, nil, errDecidedAlready 469 } 470 c.maxIncomingPayload = channelMaxPacket 471 confirm := channelOpenConfirmMsg{ 472 PeersId: c.remoteId, 473 MyId: c.localId, 474 MyWindow: c.myWindow, 475 MaxPacketSize: c.maxIncomingPayload, 476 } 477 c.decided = true 478 if err := c.sendMessage(confirm); err != nil { 479 return nil, nil, err 480 } 481 482 return c, c.incomingRequests, nil 483 } 484 485 func (ch *channel) Reject(reason RejectionReason, message string) error { 486 if ch.decided { 487 return errDecidedAlready 488 } 489 reject := channelOpenFailureMsg{ 490 PeersId: ch.remoteId, 491 Reason: reason, 492 Message: message, 493 Language: "en", 494 } 495 ch.decided = true 496 return ch.sendMessage(reject) 497 } 498 499 func (ch *channel) Read(data []byte) (int, error) { 500 if !ch.decided { 501 return 0, errUndecided 502 } 503 return ch.ReadExtended(data, 0) 504 } 505 506 func (ch *channel) Write(data []byte) (int, error) { 507 if !ch.decided { 508 return 0, errUndecided 509 } 510 return ch.WriteExtended(data, 0) 511 } 512 513 func (ch *channel) CloseWrite() error { 514 if !ch.decided { 515 return errUndecided 516 } 517 ch.sentEOF = true 518 return ch.sendMessage(channelEOFMsg{ 519 PeersId: ch.remoteId}) 520 } 521 522 func (ch *channel) Close() error { 523 if !ch.decided { 524 return errUndecided 525 } 526 527 return ch.sendMessage(channelCloseMsg{ 528 PeersId: ch.remoteId}) 529 } 530 531 // Extended returns an io.ReadWriter that sends and receives data on the given, 532 // SSH extended stream. Such streams are used, for example, for stderr. 533 func (ch *channel) Extended(code uint32) io.ReadWriter { 534 if !ch.decided { 535 return nil 536 } 537 return &extChannel{code, ch} 538 } 539 540 func (ch *channel) Stderr() io.ReadWriter { 541 return ch.Extended(1) 542 } 543 544 func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { 545 if !ch.decided { 546 return false, errUndecided 547 } 548 549 if wantReply { 550 ch.sentRequestMu.Lock() 551 defer ch.sentRequestMu.Unlock() 552 } 553 554 msg := channelRequestMsg{ 555 PeersId: ch.remoteId, 556 Request: name, 557 WantReply: wantReply, 558 RequestSpecificData: payload, 559 } 560 561 if err := ch.sendMessage(msg); err != nil { 562 return false, err 563 } 564 565 if wantReply { 566 m, ok := (<-ch.msg) 567 if !ok { 568 return false, io.EOF 569 } 570 switch m.(type) { 571 case *channelRequestFailureMsg: 572 return false, nil 573 case *channelRequestSuccessMsg: 574 return true, nil 575 default: 576 return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", m) 577 } 578 } 579 580 return false, nil 581 } 582 583 // ackRequest either sends an ack or nack to the channel request. 584 func (ch *channel) ackRequest(ok bool) error { 585 if !ch.decided { 586 return errUndecided 587 } 588 589 var msg interface{} 590 if !ok { 591 msg = channelRequestFailureMsg{ 592 PeersId: ch.remoteId, 593 } 594 } else { 595 msg = channelRequestSuccessMsg{ 596 PeersId: ch.remoteId, 597 } 598 } 599 return ch.sendMessage(msg) 600 } 601 602 func (ch *channel) ChannelType() string { 603 return ch.chanType 604 } 605 606 func (ch *channel) ExtraData() []byte { 607 return ch.extraData 608 }