github.com/pkg/sftp@v1.13.6/internal/encoding/ssh/filexfer/packets.go (about)

     1  package sshfx
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  )
     7  
     8  // smallBufferSize is an initial allocation minimal capacity.
     9  const smallBufferSize = 64
    10  
    11  // RawPacket implements the general packet format from draft-ietf-secsh-filexfer-02
    12  //
    13  // RawPacket is intended for use in clients receiving responses,
    14  // where a response will be expected to be of a limited number of types,
    15  // and unmarshaling unknown/unexpected response packets is unnecessary.
    16  //
    17  // For servers expecting to receive arbitrary request packet types,
    18  // use RequestPacket.
    19  //
    20  // Defined in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-3
    21  type RawPacket struct {
    22  	PacketType PacketType
    23  	RequestID  uint32
    24  
    25  	Data Buffer
    26  }
    27  
    28  // Type returns the Type field defining the SSH_FXP_xy type for this packet.
    29  func (p *RawPacket) Type() PacketType {
    30  	return p.PacketType
    31  }
    32  
    33  // Reset clears the pointers and reference-semantic variables of RawPacket,
    34  // releasing underlying resources, and making them and the RawPacket suitable to be reused,
    35  // so long as no other references have been kept.
    36  func (p *RawPacket) Reset() {
    37  	p.Data = Buffer{}
    38  }
    39  
    40  // MarshalPacket returns p as a two-part binary encoding of p.
    41  //
    42  // The internal p.RequestID is overridden by the reqid argument.
    43  func (p *RawPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
    44  	buf := NewBuffer(b)
    45  	if buf.Cap() < 9 {
    46  		buf = NewMarshalBuffer(0)
    47  	}
    48  
    49  	buf.StartPacket(p.PacketType, reqid)
    50  
    51  	return buf.Packet(p.Data.Bytes())
    52  }
    53  
    54  // MarshalBinary returns p as the binary encoding of p.
    55  //
    56  // This is a convenience implementation primarily intended for tests,
    57  // because it is inefficient with allocations.
    58  func (p *RawPacket) MarshalBinary() ([]byte, error) {
    59  	return ComposePacket(p.MarshalPacket(p.RequestID, nil))
    60  }
    61  
    62  // UnmarshalFrom decodes a RawPacket from the given Buffer into p.
    63  //
    64  // The Data field will alias the passed in Buffer,
    65  // so the buffer passed in should not be reused before RawPacket.Reset().
    66  func (p *RawPacket) UnmarshalFrom(buf *Buffer) error {
    67  	*p = RawPacket{
    68  		PacketType: PacketType(buf.ConsumeUint8()),
    69  		RequestID:  buf.ConsumeUint32(),
    70  	}
    71  
    72  	p.Data = *buf
    73  
    74  	return buf.Err
    75  }
    76  
    77  // UnmarshalBinary decodes a full raw packet out of the given data.
    78  // It is assumed that the uint32(length) has already been consumed to receive the data.
    79  //
    80  // This is a convenience implementation primarily intended for tests,
    81  // because this must clone the given data byte slice,
    82  // as Data is not allowed to alias any part of the data byte slice.
    83  func (p *RawPacket) UnmarshalBinary(data []byte) error {
    84  	clone := make([]byte, len(data))
    85  	n := copy(clone, data)
    86  	return p.UnmarshalFrom(NewBuffer(clone[:n]))
    87  }
    88  
    89  // readPacket reads a uint32 length-prefixed binary data packet from r.
    90  // using the given byte slice as a backing array.
    91  //
    92  // If the packet length read from r is bigger than maxPacketLength,
    93  // or greater than math.MaxInt32 on a 32-bit implementation,
    94  // then a `ErrLongPacket` error will be returned.
    95  //
    96  // If the given byte slice is insufficient to hold the packet,
    97  // then it will be extended to fill the packet size.
    98  func readPacket(r io.Reader, b []byte, maxPacketLength uint32) ([]byte, error) {
    99  	if cap(b) < 4 {
   100  		// We will need allocate our own buffer just for reading the packet length.
   101  
   102  		// However, we don’t really want to allocate an extremely narrow buffer (4-bytes),
   103  		// and cause unnecessary allocation churn from both length reads and small packet reads,
   104  		// so we use smallBufferSize from the bytes package as a reasonable guess.
   105  
   106  		// But if callers really do want to force narrow throw-away allocation of every packet body,
   107  		// they can do so with a buffer of capacity 4.
   108  		b = make([]byte, smallBufferSize)
   109  	}
   110  
   111  	if _, err := io.ReadFull(r, b[:4]); err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	length := unmarshalUint32(b)
   116  	if int(length) < 5 {
   117  		// Must have at least uint8(type) and uint32(request-id)
   118  
   119  		if int(length) < 0 {
   120  			// Only possible when strconv.IntSize == 32,
   121  			// the packet length is longer than math.MaxInt32,
   122  			// and thus longer than any possible slice.
   123  			return nil, ErrLongPacket
   124  		}
   125  
   126  		return nil, ErrShortPacket
   127  	}
   128  	if length > maxPacketLength {
   129  		return nil, ErrLongPacket
   130  	}
   131  
   132  	if int(length) > cap(b) {
   133  		// We know int(length) must be positive, because of tests above.
   134  		b = make([]byte, length)
   135  	}
   136  
   137  	n, err := io.ReadFull(r, b[:length])
   138  	return b[:n], err
   139  }
   140  
   141  // ReadFrom provides a simple functional packet reader,
   142  // using the given byte slice as a backing array.
   143  //
   144  // To protect against potential denial of service attacks,
   145  // if the read packet length is longer than maxPacketLength,
   146  // then no packet data will be read, and ErrLongPacket will be returned.
   147  // (On 32-bit int architectures, all packets >= 2^31 in length
   148  // will return ErrLongPacket regardless of maxPacketLength.)
   149  //
   150  // If the read packet length is longer than cap(b),
   151  // then a throw-away slice will allocated to meet the exact packet length.
   152  // This can be used to limit the length of reused buffers,
   153  // while still allowing reception of occasional large packets.
   154  //
   155  // The Data field may alias the passed in byte slice,
   156  // so the byte slice passed in should not be reused before RawPacket.Reset().
   157  func (p *RawPacket) ReadFrom(r io.Reader, b []byte, maxPacketLength uint32) error {
   158  	b, err := readPacket(r, b, maxPacketLength)
   159  	if err != nil {
   160  		return err
   161  	}
   162  
   163  	return p.UnmarshalFrom(NewBuffer(b))
   164  }
   165  
   166  // RequestPacket implements the general packet format from draft-ietf-secsh-filexfer-02
   167  // but also automatically decode/encodes valid request packets (2 < type < 100 || type == 200).
   168  //
   169  // RequestPacket is intended for use in servers receiving requests,
   170  // where any arbitrary request may be received, and so decoding them automatically
   171  // is useful.
   172  //
   173  // For clients expecting to receive specific response packet types,
   174  // where automatic unmarshaling of the packet body does not make sense,
   175  // use RawPacket.
   176  //
   177  // Defined in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-3
   178  type RequestPacket struct {
   179  	RequestID uint32
   180  
   181  	Request Packet
   182  }
   183  
   184  // Type returns the SSH_FXP_xy value associated with the underlying packet.
   185  func (p *RequestPacket) Type() PacketType {
   186  	return p.Request.Type()
   187  }
   188  
   189  // Reset clears the pointers and reference-semantic variables in RequestPacket,
   190  // releasing underlying resources, and making them and the RequestPacket suitable to be reused,
   191  // so long as no other references have been kept.
   192  func (p *RequestPacket) Reset() {
   193  	p.Request = nil
   194  }
   195  
   196  // MarshalPacket returns p as a two-part binary encoding of p.
   197  //
   198  // The internal p.RequestID is overridden by the reqid argument.
   199  func (p *RequestPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) {
   200  	if p.Request == nil {
   201  		return nil, nil, errors.New("empty request packet")
   202  	}
   203  
   204  	return p.Request.MarshalPacket(reqid, b)
   205  }
   206  
   207  // MarshalBinary returns p as the binary encoding of p.
   208  //
   209  // This is a convenience implementation primarily intended for tests,
   210  // because it is inefficient with allocations.
   211  func (p *RequestPacket) MarshalBinary() ([]byte, error) {
   212  	return ComposePacket(p.MarshalPacket(p.RequestID, nil))
   213  }
   214  
   215  // UnmarshalFrom decodes a RequestPacket from the given Buffer into p.
   216  //
   217  // The Request field may alias the passed in Buffer, (e.g. SSH_FXP_WRITE),
   218  // so the buffer passed in should not be reused before RequestPacket.Reset().
   219  func (p *RequestPacket) UnmarshalFrom(buf *Buffer) error {
   220  	typ := PacketType(buf.ConsumeUint8())
   221  	if buf.Err != nil {
   222  		return buf.Err
   223  	}
   224  
   225  	req, err := newPacketFromType(typ)
   226  	if err != nil {
   227  		return err
   228  	}
   229  
   230  	*p = RequestPacket{
   231  		RequestID: buf.ConsumeUint32(),
   232  		Request:   req,
   233  	}
   234  
   235  	return p.Request.UnmarshalPacketBody(buf)
   236  }
   237  
   238  // UnmarshalBinary decodes a full request packet out of the given data.
   239  // It is assumed that the uint32(length) has already been consumed to receive the data.
   240  //
   241  // This is a convenience implementation primarily intended for tests,
   242  // because this must clone the given data byte slice,
   243  // as Request is not allowed to alias any part of the data byte slice.
   244  func (p *RequestPacket) UnmarshalBinary(data []byte) error {
   245  	clone := make([]byte, len(data))
   246  	n := copy(clone, data)
   247  	return p.UnmarshalFrom(NewBuffer(clone[:n]))
   248  }
   249  
   250  // ReadFrom provides a simple functional packet reader,
   251  // using the given byte slice as a backing array.
   252  //
   253  // To protect against potential denial of service attacks,
   254  // if the read packet length is longer than maxPacketLength,
   255  // then no packet data will be read, and ErrLongPacket will be returned.
   256  // (On 32-bit int architectures, all packets >= 2^31 in length
   257  // will return ErrLongPacket regardless of maxPacketLength.)
   258  //
   259  // If the read packet length is longer than cap(b),
   260  // then a throw-away slice will allocated to meet the exact packet length.
   261  // This can be used to limit the length of reused buffers,
   262  // while still allowing reception of occasional large packets.
   263  //
   264  // The Request field may alias the passed in byte slice,
   265  // so the byte slice passed in should not be reused before RawPacket.Reset().
   266  func (p *RequestPacket) ReadFrom(r io.Reader, b []byte, maxPacketLength uint32) error {
   267  	b, err := readPacket(r, b, maxPacketLength)
   268  	if err != nil {
   269  		return err
   270  	}
   271  
   272  	return p.UnmarshalFrom(NewBuffer(b))
   273  }