| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | // Copyright 2011 The Go Authors. All rights reserved. | 
					
						
							|  |  |  | // Use of this source code is governed by a BSD-style | 
					
						
							|  |  |  | // license that can be found in the LICENSE file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package ssh | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"encoding/binary" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"math/big" | 
					
						
							|  |  |  | 	"reflect" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // These are SSH message type numbers. They are scattered around several | 
					
						
							|  |  |  | // documents but many were taken from [SSH-PARAMETERS]. | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	msgIgnore        = 2 | 
					
						
							|  |  |  | 	msgUnimplemented = 3 | 
					
						
							|  |  |  | 	msgDebug         = 4 | 
					
						
							|  |  |  | 	msgNewKeys       = 21 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SSH messages: | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // These structures mirror the wire format of the corresponding SSH messages. | 
					
						
							|  |  |  | // They are marshaled using reflection with the marshal and unmarshal functions | 
					
						
							|  |  |  | // in this file. The only wrinkle is that a final member of type []byte with a | 
					
						
							|  |  |  | // ssh tag of "rest" receives the remainder of a packet when unmarshaling. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4253, section 11.1. | 
					
						
							|  |  |  | const msgDisconnect = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // disconnectMsg is the message that signals a disconnect. It is also | 
					
						
							|  |  |  | // the error type returned from mux.Wait() | 
					
						
							|  |  |  | type disconnectMsg struct { | 
					
						
							|  |  |  | 	Reason   uint32 `sshtype:"1"` | 
					
						
							|  |  |  | 	Message  string | 
					
						
							|  |  |  | 	Language string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *disconnectMsg) Error() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4253, section 7.1. | 
					
						
							|  |  |  | const msgKexInit = 20 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type kexInitMsg struct { | 
					
						
							|  |  |  | 	Cookie                  [16]byte `sshtype:"20"` | 
					
						
							|  |  |  | 	KexAlgos                []string | 
					
						
							|  |  |  | 	ServerHostKeyAlgos      []string | 
					
						
							|  |  |  | 	CiphersClientServer     []string | 
					
						
							|  |  |  | 	CiphersServerClient     []string | 
					
						
							|  |  |  | 	MACsClientServer        []string | 
					
						
							|  |  |  | 	MACsServerClient        []string | 
					
						
							|  |  |  | 	CompressionClientServer []string | 
					
						
							|  |  |  | 	CompressionServerClient []string | 
					
						
							|  |  |  | 	LanguagesClientServer   []string | 
					
						
							|  |  |  | 	LanguagesServerClient   []string | 
					
						
							|  |  |  | 	FirstKexFollows         bool | 
					
						
							|  |  |  | 	Reserved                uint32 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4253, section 8. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-30 10:45:34 +01:00
										 |  |  | // Diffie-Hellman | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | const msgKexDHInit = 30 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type kexDHInitMsg struct { | 
					
						
							|  |  |  | 	X *big.Int `sshtype:"30"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const msgKexECDHInit = 30 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type kexECDHInitMsg struct { | 
					
						
							|  |  |  | 	ClientPubKey []byte `sshtype:"30"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const msgKexECDHReply = 31 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type kexECDHReplyMsg struct { | 
					
						
							|  |  |  | 	HostKey         []byte `sshtype:"31"` | 
					
						
							|  |  |  | 	EphemeralPubKey []byte | 
					
						
							|  |  |  | 	Signature       []byte | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const msgKexDHReply = 31 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type kexDHReplyMsg struct { | 
					
						
							|  |  |  | 	HostKey   []byte `sshtype:"31"` | 
					
						
							|  |  |  | 	Y         *big.Int | 
					
						
							|  |  |  | 	Signature []byte | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4419, section 5. | 
					
						
							|  |  |  | const msgKexDHGexGroup = 31 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type kexDHGexGroupMsg struct { | 
					
						
							|  |  |  | 	P *big.Int `sshtype:"31"` | 
					
						
							|  |  |  | 	G *big.Int | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const msgKexDHGexInit = 32 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type kexDHGexInitMsg struct { | 
					
						
							|  |  |  | 	X *big.Int `sshtype:"32"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const msgKexDHGexReply = 33 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type kexDHGexReplyMsg struct { | 
					
						
							|  |  |  | 	HostKey   []byte `sshtype:"33"` | 
					
						
							|  |  |  | 	Y         *big.Int | 
					
						
							|  |  |  | 	Signature []byte | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const msgKexDHGexRequest = 34 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type kexDHGexRequestMsg struct { | 
					
						
							|  |  |  | 	MinBits      uint32 `sshtype:"34"` | 
					
						
							|  |  |  | 	PreferedBits uint32 | 
					
						
							|  |  |  | 	MaxBits      uint32 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4253, section 10. | 
					
						
							|  |  |  | const msgServiceRequest = 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type serviceRequestMsg struct { | 
					
						
							|  |  |  | 	Service string `sshtype:"5"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4253, section 10. | 
					
						
							|  |  |  | const msgServiceAccept = 6 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type serviceAcceptMsg struct { | 
					
						
							|  |  |  | 	Service string `sshtype:"6"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-02 14:05:18 +01:00
										 |  |  | // See RFC 8308, section 2.3 | 
					
						
							|  |  |  | const msgExtInfo = 7 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type extInfoMsg struct { | 
					
						
							|  |  |  | 	NumExtensions uint32 `sshtype:"7"` | 
					
						
							|  |  |  | 	Payload       []byte `ssh:"rest"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | // See RFC 4252, section 5. | 
					
						
							|  |  |  | const msgUserAuthRequest = 50 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type userAuthRequestMsg struct { | 
					
						
							|  |  |  | 	User    string `sshtype:"50"` | 
					
						
							|  |  |  | 	Service string | 
					
						
							|  |  |  | 	Method  string | 
					
						
							|  |  |  | 	Payload []byte `ssh:"rest"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Used for debug printouts of packets. | 
					
						
							|  |  |  | type userAuthSuccessMsg struct { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4252, section 5.1 | 
					
						
							|  |  |  | const msgUserAuthFailure = 51 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type userAuthFailureMsg struct { | 
					
						
							|  |  |  | 	Methods        []string `sshtype:"51"` | 
					
						
							|  |  |  | 	PartialSuccess bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4252, section 5.1 | 
					
						
							|  |  |  | const msgUserAuthSuccess = 52 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4252, section 5.4 | 
					
						
							|  |  |  | const msgUserAuthBanner = 53 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type userAuthBannerMsg struct { | 
					
						
							|  |  |  | 	Message string `sshtype:"53"` | 
					
						
							|  |  |  | 	// unused, but required to allow message parsing | 
					
						
							|  |  |  | 	Language string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4256, section 3.2 | 
					
						
							|  |  |  | const msgUserAuthInfoRequest = 60 | 
					
						
							|  |  |  | const msgUserAuthInfoResponse = 61 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type userAuthInfoRequestMsg struct { | 
					
						
							| 
									
										
										
										
											2022-05-02 14:05:18 +01:00
										 |  |  | 	Name        string `sshtype:"60"` | 
					
						
							|  |  |  | 	Instruction string | 
					
						
							|  |  |  | 	Language    string | 
					
						
							|  |  |  | 	NumPrompts  uint32 | 
					
						
							|  |  |  | 	Prompts     []byte `ssh:"rest"` | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4254, section 5.1. | 
					
						
							|  |  |  | const msgChannelOpen = 90 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type channelOpenMsg struct { | 
					
						
							|  |  |  | 	ChanType         string `sshtype:"90"` | 
					
						
							|  |  |  | 	PeersID          uint32 | 
					
						
							|  |  |  | 	PeersWindow      uint32 | 
					
						
							|  |  |  | 	MaxPacketSize    uint32 | 
					
						
							|  |  |  | 	TypeSpecificData []byte `ssh:"rest"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const msgChannelExtendedData = 95 | 
					
						
							|  |  |  | const msgChannelData = 94 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Used for debug print outs of packets. | 
					
						
							|  |  |  | type channelDataMsg struct { | 
					
						
							|  |  |  | 	PeersID uint32 `sshtype:"94"` | 
					
						
							|  |  |  | 	Length  uint32 | 
					
						
							|  |  |  | 	Rest    []byte `ssh:"rest"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4254, section 5.1. | 
					
						
							|  |  |  | const msgChannelOpenConfirm = 91 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type channelOpenConfirmMsg struct { | 
					
						
							|  |  |  | 	PeersID          uint32 `sshtype:"91"` | 
					
						
							|  |  |  | 	MyID             uint32 | 
					
						
							|  |  |  | 	MyWindow         uint32 | 
					
						
							|  |  |  | 	MaxPacketSize    uint32 | 
					
						
							|  |  |  | 	TypeSpecificData []byte `ssh:"rest"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4254, section 5.1. | 
					
						
							|  |  |  | const msgChannelOpenFailure = 92 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type channelOpenFailureMsg struct { | 
					
						
							|  |  |  | 	PeersID  uint32 `sshtype:"92"` | 
					
						
							|  |  |  | 	Reason   RejectionReason | 
					
						
							|  |  |  | 	Message  string | 
					
						
							|  |  |  | 	Language string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const msgChannelRequest = 98 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type channelRequestMsg struct { | 
					
						
							|  |  |  | 	PeersID             uint32 `sshtype:"98"` | 
					
						
							|  |  |  | 	Request             string | 
					
						
							|  |  |  | 	WantReply           bool | 
					
						
							|  |  |  | 	RequestSpecificData []byte `ssh:"rest"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4254, section 5.4. | 
					
						
							|  |  |  | const msgChannelSuccess = 99 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type channelRequestSuccessMsg struct { | 
					
						
							|  |  |  | 	PeersID uint32 `sshtype:"99"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4254, section 5.4. | 
					
						
							|  |  |  | const msgChannelFailure = 100 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type channelRequestFailureMsg struct { | 
					
						
							|  |  |  | 	PeersID uint32 `sshtype:"100"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4254, section 5.3 | 
					
						
							|  |  |  | const msgChannelClose = 97 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type channelCloseMsg struct { | 
					
						
							|  |  |  | 	PeersID uint32 `sshtype:"97"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4254, section 5.3 | 
					
						
							|  |  |  | const msgChannelEOF = 96 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type channelEOFMsg struct { | 
					
						
							|  |  |  | 	PeersID uint32 `sshtype:"96"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4254, section 4 | 
					
						
							|  |  |  | const msgGlobalRequest = 80 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type globalRequestMsg struct { | 
					
						
							|  |  |  | 	Type      string `sshtype:"80"` | 
					
						
							|  |  |  | 	WantReply bool | 
					
						
							|  |  |  | 	Data      []byte `ssh:"rest"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4254, section 4 | 
					
						
							|  |  |  | const msgRequestSuccess = 81 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type globalRequestSuccessMsg struct { | 
					
						
							|  |  |  | 	Data []byte `ssh:"rest" sshtype:"81"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4254, section 4 | 
					
						
							|  |  |  | const msgRequestFailure = 82 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type globalRequestFailureMsg struct { | 
					
						
							|  |  |  | 	Data []byte `ssh:"rest" sshtype:"82"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4254, section 5.2 | 
					
						
							|  |  |  | const msgChannelWindowAdjust = 93 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type windowAdjustMsg struct { | 
					
						
							|  |  |  | 	PeersID         uint32 `sshtype:"93"` | 
					
						
							|  |  |  | 	AdditionalBytes uint32 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4252, section 7 | 
					
						
							|  |  |  | const msgUserAuthPubKeyOk = 60 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type userAuthPubKeyOkMsg struct { | 
					
						
							|  |  |  | 	Algo   string `sshtype:"60"` | 
					
						
							|  |  |  | 	PubKey []byte | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4462, section 3 | 
					
						
							|  |  |  | const msgUserAuthGSSAPIResponse = 60 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type userAuthGSSAPIResponse struct { | 
					
						
							|  |  |  | 	SupportMech []byte `sshtype:"60"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const msgUserAuthGSSAPIToken = 61 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type userAuthGSSAPIToken struct { | 
					
						
							|  |  |  | 	Token []byte `sshtype:"61"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const msgUserAuthGSSAPIMIC = 66 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type userAuthGSSAPIMIC struct { | 
					
						
							|  |  |  | 	MIC []byte `sshtype:"66"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4462, section 3.9 | 
					
						
							|  |  |  | const msgUserAuthGSSAPIErrTok = 64 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type userAuthGSSAPIErrTok struct { | 
					
						
							|  |  |  | 	ErrorToken []byte `sshtype:"64"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // See RFC 4462, section 3.8 | 
					
						
							|  |  |  | const msgUserAuthGSSAPIError = 65 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type userAuthGSSAPIError struct { | 
					
						
							|  |  |  | 	MajorStatus uint32 `sshtype:"65"` | 
					
						
							|  |  |  | 	MinorStatus uint32 | 
					
						
							|  |  |  | 	Message     string | 
					
						
							|  |  |  | 	LanguageTag string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-09 10:13:09 +02:00
										 |  |  | // Transport layer OpenSSH extension. See [PROTOCOL], section 1.9 | 
					
						
							|  |  |  | const msgPing = 192 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type pingMsg struct { | 
					
						
							|  |  |  | 	Data string `sshtype:"192"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Transport layer OpenSSH extension. See [PROTOCOL], section 1.9 | 
					
						
							|  |  |  | const msgPong = 193 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type pongMsg struct { | 
					
						
							|  |  |  | 	Data string `sshtype:"193"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | // typeTags returns the possible type bytes for the given reflect.Type, which | 
					
						
							|  |  |  | // should be a struct. The possible values are separated by a '|' character. | 
					
						
							|  |  |  | func typeTags(structType reflect.Type) (tags []byte) { | 
					
						
							|  |  |  | 	tagStr := structType.Field(0).Tag.Get("sshtype") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tag := range strings.Split(tagStr, "|") { | 
					
						
							|  |  |  | 		i, err := strconv.Atoi(tag) | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			tags = append(tags, byte(i)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return tags | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func fieldError(t reflect.Type, field int, problem string) error { | 
					
						
							|  |  |  | 	if problem != "" { | 
					
						
							|  |  |  | 		problem = ": " + problem | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var errShortRead = errors.New("ssh: short read") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Unmarshal parses data in SSH wire format into a structure. The out | 
					
						
							|  |  |  | // argument should be a pointer to struct. If the first member of the | 
					
						
							|  |  |  | // struct has the "sshtype" tag set to a '|'-separated set of numbers | 
					
						
							|  |  |  | // in decimal, the packet must start with one of those numbers. In | 
					
						
							|  |  |  | // case of error, Unmarshal returns a ParseError or | 
					
						
							|  |  |  | // UnexpectedMessageError. | 
					
						
							|  |  |  | func Unmarshal(data []byte, out interface{}) error { | 
					
						
							|  |  |  | 	v := reflect.ValueOf(out).Elem() | 
					
						
							|  |  |  | 	structType := v.Type() | 
					
						
							|  |  |  | 	expectedTypes := typeTags(structType) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var expectedType byte | 
					
						
							|  |  |  | 	if len(expectedTypes) > 0 { | 
					
						
							|  |  |  | 		expectedType = expectedTypes[0] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(data) == 0 { | 
					
						
							|  |  |  | 		return parseError(expectedType) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(expectedTypes) > 0 { | 
					
						
							|  |  |  | 		goodType := false | 
					
						
							|  |  |  | 		for _, e := range expectedTypes { | 
					
						
							|  |  |  | 			if e > 0 && data[0] == e { | 
					
						
							|  |  |  | 				goodType = true | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if !goodType { | 
					
						
							|  |  |  | 			return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		data = data[1:] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ok bool | 
					
						
							|  |  |  | 	for i := 0; i < v.NumField(); i++ { | 
					
						
							|  |  |  | 		field := v.Field(i) | 
					
						
							|  |  |  | 		t := field.Type() | 
					
						
							|  |  |  | 		switch t.Kind() { | 
					
						
							|  |  |  | 		case reflect.Bool: | 
					
						
							|  |  |  | 			if len(data) < 1 { | 
					
						
							|  |  |  | 				return errShortRead | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			field.SetBool(data[0] != 0) | 
					
						
							|  |  |  | 			data = data[1:] | 
					
						
							|  |  |  | 		case reflect.Array: | 
					
						
							|  |  |  | 			if t.Elem().Kind() != reflect.Uint8 { | 
					
						
							|  |  |  | 				return fieldError(structType, i, "array of unsupported type") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if len(data) < t.Len() { | 
					
						
							|  |  |  | 				return errShortRead | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for j, n := 0, t.Len(); j < n; j++ { | 
					
						
							|  |  |  | 				field.Index(j).Set(reflect.ValueOf(data[j])) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			data = data[t.Len():] | 
					
						
							|  |  |  | 		case reflect.Uint64: | 
					
						
							|  |  |  | 			var u64 uint64 | 
					
						
							|  |  |  | 			if u64, data, ok = parseUint64(data); !ok { | 
					
						
							|  |  |  | 				return errShortRead | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			field.SetUint(u64) | 
					
						
							|  |  |  | 		case reflect.Uint32: | 
					
						
							|  |  |  | 			var u32 uint32 | 
					
						
							|  |  |  | 			if u32, data, ok = parseUint32(data); !ok { | 
					
						
							|  |  |  | 				return errShortRead | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			field.SetUint(uint64(u32)) | 
					
						
							|  |  |  | 		case reflect.Uint8: | 
					
						
							|  |  |  | 			if len(data) < 1 { | 
					
						
							|  |  |  | 				return errShortRead | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			field.SetUint(uint64(data[0])) | 
					
						
							|  |  |  | 			data = data[1:] | 
					
						
							|  |  |  | 		case reflect.String: | 
					
						
							|  |  |  | 			var s []byte | 
					
						
							|  |  |  | 			if s, data, ok = parseString(data); !ok { | 
					
						
							|  |  |  | 				return fieldError(structType, i, "") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			field.SetString(string(s)) | 
					
						
							|  |  |  | 		case reflect.Slice: | 
					
						
							|  |  |  | 			switch t.Elem().Kind() { | 
					
						
							|  |  |  | 			case reflect.Uint8: | 
					
						
							|  |  |  | 				if structType.Field(i).Tag.Get("ssh") == "rest" { | 
					
						
							|  |  |  | 					field.Set(reflect.ValueOf(data)) | 
					
						
							|  |  |  | 					data = nil | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					var s []byte | 
					
						
							|  |  |  | 					if s, data, ok = parseString(data); !ok { | 
					
						
							|  |  |  | 						return errShortRead | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					field.Set(reflect.ValueOf(s)) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			case reflect.String: | 
					
						
							|  |  |  | 				var nl []string | 
					
						
							|  |  |  | 				if nl, data, ok = parseNameList(data); !ok { | 
					
						
							|  |  |  | 					return errShortRead | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				field.Set(reflect.ValueOf(nl)) | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				return fieldError(structType, i, "slice of unsupported type") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case reflect.Ptr: | 
					
						
							|  |  |  | 			if t == bigIntType { | 
					
						
							|  |  |  | 				var n *big.Int | 
					
						
							|  |  |  | 				if n, data, ok = parseInt(data); !ok { | 
					
						
							|  |  |  | 					return errShortRead | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				field.Set(reflect.ValueOf(n)) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return fieldError(structType, i, "pointer to unsupported type") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(data) != 0 { | 
					
						
							|  |  |  | 		return parseError(expectedType) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Marshal serializes the message in msg to SSH wire format.  The msg | 
					
						
							|  |  |  | // argument should be a struct or pointer to struct. If the first | 
					
						
							|  |  |  | // member has the "sshtype" tag set to a number in decimal, that | 
					
						
							|  |  |  | // number is prepended to the result. If the last of member has the | 
					
						
							|  |  |  | // "ssh" tag set to "rest", its contents are appended to the output. | 
					
						
							|  |  |  | func Marshal(msg interface{}) []byte { | 
					
						
							|  |  |  | 	out := make([]byte, 0, 64) | 
					
						
							|  |  |  | 	return marshalStruct(out, msg) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func marshalStruct(out []byte, msg interface{}) []byte { | 
					
						
							|  |  |  | 	v := reflect.Indirect(reflect.ValueOf(msg)) | 
					
						
							|  |  |  | 	msgTypes := typeTags(v.Type()) | 
					
						
							|  |  |  | 	if len(msgTypes) > 0 { | 
					
						
							|  |  |  | 		out = append(out, msgTypes[0]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, n := 0, v.NumField(); i < n; i++ { | 
					
						
							|  |  |  | 		field := v.Field(i) | 
					
						
							|  |  |  | 		switch t := field.Type(); t.Kind() { | 
					
						
							|  |  |  | 		case reflect.Bool: | 
					
						
							|  |  |  | 			var v uint8 | 
					
						
							|  |  |  | 			if field.Bool() { | 
					
						
							|  |  |  | 				v = 1 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			out = append(out, v) | 
					
						
							|  |  |  | 		case reflect.Array: | 
					
						
							|  |  |  | 			if t.Elem().Kind() != reflect.Uint8 { | 
					
						
							|  |  |  | 				panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface())) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for j, l := 0, t.Len(); j < l; j++ { | 
					
						
							|  |  |  | 				out = append(out, uint8(field.Index(j).Uint())) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case reflect.Uint32: | 
					
						
							|  |  |  | 			out = appendU32(out, uint32(field.Uint())) | 
					
						
							|  |  |  | 		case reflect.Uint64: | 
					
						
							|  |  |  | 			out = appendU64(out, uint64(field.Uint())) | 
					
						
							|  |  |  | 		case reflect.Uint8: | 
					
						
							|  |  |  | 			out = append(out, uint8(field.Uint())) | 
					
						
							|  |  |  | 		case reflect.String: | 
					
						
							|  |  |  | 			s := field.String() | 
					
						
							|  |  |  | 			out = appendInt(out, len(s)) | 
					
						
							|  |  |  | 			out = append(out, s...) | 
					
						
							|  |  |  | 		case reflect.Slice: | 
					
						
							|  |  |  | 			switch t.Elem().Kind() { | 
					
						
							|  |  |  | 			case reflect.Uint8: | 
					
						
							|  |  |  | 				if v.Type().Field(i).Tag.Get("ssh") != "rest" { | 
					
						
							|  |  |  | 					out = appendInt(out, field.Len()) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				out = append(out, field.Bytes()...) | 
					
						
							|  |  |  | 			case reflect.String: | 
					
						
							|  |  |  | 				offset := len(out) | 
					
						
							|  |  |  | 				out = appendU32(out, 0) | 
					
						
							|  |  |  | 				if n := field.Len(); n > 0 { | 
					
						
							|  |  |  | 					for j := 0; j < n; j++ { | 
					
						
							|  |  |  | 						f := field.Index(j) | 
					
						
							|  |  |  | 						if j != 0 { | 
					
						
							|  |  |  | 							out = append(out, ',') | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						out = append(out, f.String()...) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					// overwrite length value | 
					
						
							|  |  |  | 					binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4)) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface())) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		case reflect.Ptr: | 
					
						
							|  |  |  | 			if t == bigIntType { | 
					
						
							|  |  |  | 				var n *big.Int | 
					
						
							|  |  |  | 				nValue := reflect.ValueOf(&n) | 
					
						
							|  |  |  | 				nValue.Elem().Set(field) | 
					
						
							|  |  |  | 				needed := intLength(n) | 
					
						
							|  |  |  | 				oldLength := len(out) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if cap(out)-len(out) < needed { | 
					
						
							|  |  |  | 					newOut := make([]byte, len(out), 2*(len(out)+needed)) | 
					
						
							|  |  |  | 					copy(newOut, out) | 
					
						
							|  |  |  | 					out = newOut | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				out = out[:oldLength+needed] | 
					
						
							|  |  |  | 				marshalInt(out[oldLength:], n) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface())) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return out | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var bigOne = big.NewInt(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func parseString(in []byte) (out, rest []byte, ok bool) { | 
					
						
							|  |  |  | 	if len(in) < 4 { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	length := binary.BigEndian.Uint32(in) | 
					
						
							|  |  |  | 	in = in[4:] | 
					
						
							|  |  |  | 	if uint32(len(in)) < length { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	out = in[:length] | 
					
						
							|  |  |  | 	rest = in[length:] | 
					
						
							|  |  |  | 	ok = true | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	comma         = []byte{','} | 
					
						
							|  |  |  | 	emptyNameList = []string{} | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func parseNameList(in []byte) (out []string, rest []byte, ok bool) { | 
					
						
							|  |  |  | 	contents, rest, ok := parseString(in) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(contents) == 0 { | 
					
						
							|  |  |  | 		out = emptyNameList | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	parts := bytes.Split(contents, comma) | 
					
						
							|  |  |  | 	out = make([]string, len(parts)) | 
					
						
							|  |  |  | 	for i, part := range parts { | 
					
						
							|  |  |  | 		out[i] = string(part) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) { | 
					
						
							|  |  |  | 	contents, rest, ok := parseString(in) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	out = new(big.Int) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(contents) > 0 && contents[0]&0x80 == 0x80 { | 
					
						
							|  |  |  | 		// This is a negative number | 
					
						
							|  |  |  | 		notBytes := make([]byte, len(contents)) | 
					
						
							|  |  |  | 		for i := range notBytes { | 
					
						
							|  |  |  | 			notBytes[i] = ^contents[i] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		out.SetBytes(notBytes) | 
					
						
							|  |  |  | 		out.Add(out, bigOne) | 
					
						
							|  |  |  | 		out.Neg(out) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// Positive number | 
					
						
							|  |  |  | 		out.SetBytes(contents) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ok = true | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func parseUint32(in []byte) (uint32, []byte, bool) { | 
					
						
							|  |  |  | 	if len(in) < 4 { | 
					
						
							|  |  |  | 		return 0, nil, false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return binary.BigEndian.Uint32(in), in[4:], true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func parseUint64(in []byte) (uint64, []byte, bool) { | 
					
						
							|  |  |  | 	if len(in) < 8 { | 
					
						
							|  |  |  | 		return 0, nil, false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return binary.BigEndian.Uint64(in), in[8:], true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func intLength(n *big.Int) int { | 
					
						
							|  |  |  | 	length := 4 /* length bytes */ | 
					
						
							|  |  |  | 	if n.Sign() < 0 { | 
					
						
							|  |  |  | 		nMinus1 := new(big.Int).Neg(n) | 
					
						
							|  |  |  | 		nMinus1.Sub(nMinus1, bigOne) | 
					
						
							|  |  |  | 		bitLen := nMinus1.BitLen() | 
					
						
							|  |  |  | 		if bitLen%8 == 0 { | 
					
						
							|  |  |  | 			// The number will need 0xff padding | 
					
						
							|  |  |  | 			length++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		length += (bitLen + 7) / 8 | 
					
						
							|  |  |  | 	} else if n.Sign() == 0 { | 
					
						
							|  |  |  | 		// A zero is the zero length string | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		bitLen := n.BitLen() | 
					
						
							|  |  |  | 		if bitLen%8 == 0 { | 
					
						
							|  |  |  | 			// The number will need 0x00 padding | 
					
						
							|  |  |  | 			length++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		length += (bitLen + 7) / 8 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return length | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func marshalUint32(to []byte, n uint32) []byte { | 
					
						
							|  |  |  | 	binary.BigEndian.PutUint32(to, n) | 
					
						
							|  |  |  | 	return to[4:] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func marshalUint64(to []byte, n uint64) []byte { | 
					
						
							|  |  |  | 	binary.BigEndian.PutUint64(to, n) | 
					
						
							|  |  |  | 	return to[8:] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func marshalInt(to []byte, n *big.Int) []byte { | 
					
						
							|  |  |  | 	lengthBytes := to | 
					
						
							|  |  |  | 	to = to[4:] | 
					
						
							|  |  |  | 	length := 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if n.Sign() < 0 { | 
					
						
							|  |  |  | 		// A negative number has to be converted to two's-complement | 
					
						
							|  |  |  | 		// form. So we'll subtract 1 and invert. If the | 
					
						
							|  |  |  | 		// most-significant-bit isn't set then we'll need to pad the | 
					
						
							|  |  |  | 		// beginning with 0xff in order to keep the number negative. | 
					
						
							|  |  |  | 		nMinus1 := new(big.Int).Neg(n) | 
					
						
							|  |  |  | 		nMinus1.Sub(nMinus1, bigOne) | 
					
						
							|  |  |  | 		bytes := nMinus1.Bytes() | 
					
						
							|  |  |  | 		for i := range bytes { | 
					
						
							|  |  |  | 			bytes[i] ^= 0xff | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if len(bytes) == 0 || bytes[0]&0x80 == 0 { | 
					
						
							|  |  |  | 			to[0] = 0xff | 
					
						
							|  |  |  | 			to = to[1:] | 
					
						
							|  |  |  | 			length++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		nBytes := copy(to, bytes) | 
					
						
							|  |  |  | 		to = to[nBytes:] | 
					
						
							|  |  |  | 		length += nBytes | 
					
						
							|  |  |  | 	} else if n.Sign() == 0 { | 
					
						
							|  |  |  | 		// A zero is the zero length string | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		bytes := n.Bytes() | 
					
						
							|  |  |  | 		if len(bytes) > 0 && bytes[0]&0x80 != 0 { | 
					
						
							|  |  |  | 			// We'll have to pad this with a 0x00 in order to | 
					
						
							|  |  |  | 			// stop it looking like a negative number. | 
					
						
							|  |  |  | 			to[0] = 0 | 
					
						
							|  |  |  | 			to = to[1:] | 
					
						
							|  |  |  | 			length++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		nBytes := copy(to, bytes) | 
					
						
							|  |  |  | 		to = to[nBytes:] | 
					
						
							|  |  |  | 		length += nBytes | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lengthBytes[0] = byte(length >> 24) | 
					
						
							|  |  |  | 	lengthBytes[1] = byte(length >> 16) | 
					
						
							|  |  |  | 	lengthBytes[2] = byte(length >> 8) | 
					
						
							|  |  |  | 	lengthBytes[3] = byte(length) | 
					
						
							|  |  |  | 	return to | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func writeInt(w io.Writer, n *big.Int) { | 
					
						
							|  |  |  | 	length := intLength(n) | 
					
						
							|  |  |  | 	buf := make([]byte, length) | 
					
						
							|  |  |  | 	marshalInt(buf, n) | 
					
						
							|  |  |  | 	w.Write(buf) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func writeString(w io.Writer, s []byte) { | 
					
						
							|  |  |  | 	var lengthBytes [4]byte | 
					
						
							|  |  |  | 	lengthBytes[0] = byte(len(s) >> 24) | 
					
						
							|  |  |  | 	lengthBytes[1] = byte(len(s) >> 16) | 
					
						
							|  |  |  | 	lengthBytes[2] = byte(len(s) >> 8) | 
					
						
							|  |  |  | 	lengthBytes[3] = byte(len(s)) | 
					
						
							|  |  |  | 	w.Write(lengthBytes[:]) | 
					
						
							|  |  |  | 	w.Write(s) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func stringLength(n int) int { | 
					
						
							|  |  |  | 	return 4 + n | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func marshalString(to []byte, s []byte) []byte { | 
					
						
							|  |  |  | 	to[0] = byte(len(s) >> 24) | 
					
						
							|  |  |  | 	to[1] = byte(len(s) >> 16) | 
					
						
							|  |  |  | 	to[2] = byte(len(s) >> 8) | 
					
						
							|  |  |  | 	to[3] = byte(len(s)) | 
					
						
							|  |  |  | 	to = to[4:] | 
					
						
							|  |  |  | 	copy(to, s) | 
					
						
							|  |  |  | 	return to[len(s):] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var bigIntType = reflect.TypeOf((*big.Int)(nil)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Decode a packet into its corresponding message. | 
					
						
							|  |  |  | func decode(packet []byte) (interface{}, error) { | 
					
						
							|  |  |  | 	var msg interface{} | 
					
						
							|  |  |  | 	switch packet[0] { | 
					
						
							|  |  |  | 	case msgDisconnect: | 
					
						
							|  |  |  | 		msg = new(disconnectMsg) | 
					
						
							|  |  |  | 	case msgServiceRequest: | 
					
						
							|  |  |  | 		msg = new(serviceRequestMsg) | 
					
						
							|  |  |  | 	case msgServiceAccept: | 
					
						
							|  |  |  | 		msg = new(serviceAcceptMsg) | 
					
						
							| 
									
										
										
										
											2022-05-02 14:05:18 +01:00
										 |  |  | 	case msgExtInfo: | 
					
						
							|  |  |  | 		msg = new(extInfoMsg) | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | 	case msgKexInit: | 
					
						
							|  |  |  | 		msg = new(kexInitMsg) | 
					
						
							|  |  |  | 	case msgKexDHInit: | 
					
						
							|  |  |  | 		msg = new(kexDHInitMsg) | 
					
						
							|  |  |  | 	case msgKexDHReply: | 
					
						
							|  |  |  | 		msg = new(kexDHReplyMsg) | 
					
						
							|  |  |  | 	case msgUserAuthRequest: | 
					
						
							|  |  |  | 		msg = new(userAuthRequestMsg) | 
					
						
							|  |  |  | 	case msgUserAuthSuccess: | 
					
						
							|  |  |  | 		return new(userAuthSuccessMsg), nil | 
					
						
							|  |  |  | 	case msgUserAuthFailure: | 
					
						
							|  |  |  | 		msg = new(userAuthFailureMsg) | 
					
						
							|  |  |  | 	case msgUserAuthPubKeyOk: | 
					
						
							|  |  |  | 		msg = new(userAuthPubKeyOkMsg) | 
					
						
							|  |  |  | 	case msgGlobalRequest: | 
					
						
							|  |  |  | 		msg = new(globalRequestMsg) | 
					
						
							|  |  |  | 	case msgRequestSuccess: | 
					
						
							|  |  |  | 		msg = new(globalRequestSuccessMsg) | 
					
						
							|  |  |  | 	case msgRequestFailure: | 
					
						
							|  |  |  | 		msg = new(globalRequestFailureMsg) | 
					
						
							|  |  |  | 	case msgChannelOpen: | 
					
						
							|  |  |  | 		msg = new(channelOpenMsg) | 
					
						
							|  |  |  | 	case msgChannelData: | 
					
						
							|  |  |  | 		msg = new(channelDataMsg) | 
					
						
							|  |  |  | 	case msgChannelOpenConfirm: | 
					
						
							|  |  |  | 		msg = new(channelOpenConfirmMsg) | 
					
						
							|  |  |  | 	case msgChannelOpenFailure: | 
					
						
							|  |  |  | 		msg = new(channelOpenFailureMsg) | 
					
						
							|  |  |  | 	case msgChannelWindowAdjust: | 
					
						
							|  |  |  | 		msg = new(windowAdjustMsg) | 
					
						
							|  |  |  | 	case msgChannelEOF: | 
					
						
							|  |  |  | 		msg = new(channelEOFMsg) | 
					
						
							|  |  |  | 	case msgChannelClose: | 
					
						
							|  |  |  | 		msg = new(channelCloseMsg) | 
					
						
							|  |  |  | 	case msgChannelRequest: | 
					
						
							|  |  |  | 		msg = new(channelRequestMsg) | 
					
						
							|  |  |  | 	case msgChannelSuccess: | 
					
						
							|  |  |  | 		msg = new(channelRequestSuccessMsg) | 
					
						
							|  |  |  | 	case msgChannelFailure: | 
					
						
							|  |  |  | 		msg = new(channelRequestFailureMsg) | 
					
						
							|  |  |  | 	case msgUserAuthGSSAPIToken: | 
					
						
							|  |  |  | 		msg = new(userAuthGSSAPIToken) | 
					
						
							|  |  |  | 	case msgUserAuthGSSAPIMIC: | 
					
						
							|  |  |  | 		msg = new(userAuthGSSAPIMIC) | 
					
						
							|  |  |  | 	case msgUserAuthGSSAPIErrTok: | 
					
						
							|  |  |  | 		msg = new(userAuthGSSAPIErrTok) | 
					
						
							|  |  |  | 	case msgUserAuthGSSAPIError: | 
					
						
							|  |  |  | 		msg = new(userAuthGSSAPIError) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return nil, unexpectedMessageError(0, packet[0]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := Unmarshal(packet, msg); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return msg, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var packetTypeNames = map[byte]string{ | 
					
						
							|  |  |  | 	msgDisconnect:          "disconnectMsg", | 
					
						
							|  |  |  | 	msgServiceRequest:      "serviceRequestMsg", | 
					
						
							|  |  |  | 	msgServiceAccept:       "serviceAcceptMsg", | 
					
						
							| 
									
										
										
										
											2022-05-02 14:05:18 +01:00
										 |  |  | 	msgExtInfo:             "extInfoMsg", | 
					
						
							| 
									
										
										
										
											2021-08-12 21:03:24 +02:00
										 |  |  | 	msgKexInit:             "kexInitMsg", | 
					
						
							|  |  |  | 	msgKexDHInit:           "kexDHInitMsg", | 
					
						
							|  |  |  | 	msgKexDHReply:          "kexDHReplyMsg", | 
					
						
							|  |  |  | 	msgUserAuthRequest:     "userAuthRequestMsg", | 
					
						
							|  |  |  | 	msgUserAuthSuccess:     "userAuthSuccessMsg", | 
					
						
							|  |  |  | 	msgUserAuthFailure:     "userAuthFailureMsg", | 
					
						
							|  |  |  | 	msgUserAuthPubKeyOk:    "userAuthPubKeyOkMsg", | 
					
						
							|  |  |  | 	msgGlobalRequest:       "globalRequestMsg", | 
					
						
							|  |  |  | 	msgRequestSuccess:      "globalRequestSuccessMsg", | 
					
						
							|  |  |  | 	msgRequestFailure:      "globalRequestFailureMsg", | 
					
						
							|  |  |  | 	msgChannelOpen:         "channelOpenMsg", | 
					
						
							|  |  |  | 	msgChannelData:         "channelDataMsg", | 
					
						
							|  |  |  | 	msgChannelOpenConfirm:  "channelOpenConfirmMsg", | 
					
						
							|  |  |  | 	msgChannelOpenFailure:  "channelOpenFailureMsg", | 
					
						
							|  |  |  | 	msgChannelWindowAdjust: "windowAdjustMsg", | 
					
						
							|  |  |  | 	msgChannelEOF:          "channelEOFMsg", | 
					
						
							|  |  |  | 	msgChannelClose:        "channelCloseMsg", | 
					
						
							|  |  |  | 	msgChannelRequest:      "channelRequestMsg", | 
					
						
							|  |  |  | 	msgChannelSuccess:      "channelRequestSuccessMsg", | 
					
						
							|  |  |  | 	msgChannelFailure:      "channelRequestFailureMsg", | 
					
						
							|  |  |  | } |