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  }