forked from lug/matterbridge
		
	Add sshchat dependencies in vendor
This commit is contained in:
		
							
								
								
									
										21
									
								
								vendor/github.com/shazow/rateio/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/shazow/rateio/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | The MIT License (MIT) | ||||||
|  |  | ||||||
|  | Copyright (c) 2015 Andrey Petrov | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | SOFTWARE. | ||||||
							
								
								
									
										29
									
								
								vendor/github.com/shazow/rateio/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/shazow/rateio/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | /* | ||||||
|  | Package rateio provides an io interfaces for rate-limiting. | ||||||
|  |  | ||||||
|  | This can be used to apply rate limiting to any type that implements an io-style interface. | ||||||
|  |  | ||||||
|  | For example, we can use it to restrict the reading rate of a net.Conn: | ||||||
|  |  | ||||||
|  | 	type limitedConn struct { | ||||||
|  | 		net.Conn | ||||||
|  | 		io.Reader // Our rate-limited io.Reader for net.Conn | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	func (r *limitedConn) Read(p []byte) (n int, err error) { | ||||||
|  | 		return r.Reader.Read(p) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// ReadLimitConn returns a net.Conn whose io.Reader interface is rate-limited by limiter. | ||||||
|  | 	func ReadLimitConn(conn net.Conn, limiter rateio.Limiter) net.Conn { | ||||||
|  | 		return &limitedConn{ | ||||||
|  | 			Conn:   conn, | ||||||
|  | 			Reader: rateio.NewReader(conn, limiter), | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | Then we can use ReadLimitConn to wrap our existing net.Conn and continue using | ||||||
|  | the wrapped version in its place. | ||||||
|  |  | ||||||
|  | */ | ||||||
|  | package rateio | ||||||
							
								
								
									
										62
									
								
								vendor/github.com/shazow/rateio/limiter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								vendor/github.com/shazow/rateio/limiter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | package rateio | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const minInt = -int(^uint(0)>>1) - 1 | ||||||
|  |  | ||||||
|  | // The error returned when the read rate exceeds our specification. | ||||||
|  | var ErrRateExceeded = errors.New("Read rate exceeded.") | ||||||
|  |  | ||||||
|  | // Limiter is an interface for a rate limiter. | ||||||
|  | // There are a few example limiters included in the package, but feel free to go wild with your own. | ||||||
|  | type Limiter interface { | ||||||
|  | 	// Apply this many bytes to the limiter, return ErrRateExceeded if the defined rate is exceeded. | ||||||
|  | 	Count(int) error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // simpleLimiter is a rate limiter that restricts Amount bytes in Frequency duration. | ||||||
|  | type simpleLimiter struct { | ||||||
|  | 	Amount    int | ||||||
|  | 	Frequency time.Duration | ||||||
|  |  | ||||||
|  | 	numRead  int | ||||||
|  | 	timeRead time.Time | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewSimpleLimiter creates a Limiter that restricts a given number of bytes per frequency. | ||||||
|  | func NewSimpleLimiter(amount int, frequency time.Duration) Limiter { | ||||||
|  | 	return &simpleLimiter{ | ||||||
|  | 		Amount:    amount, | ||||||
|  | 		Frequency: frequency, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewGracefulLimiter returns a Limiter that is the same as a | ||||||
|  | // SimpleLimiter but adds a grace period at the start of the rate | ||||||
|  | // limiting where it allows unlimited bytes to be read during that | ||||||
|  | // period. | ||||||
|  | func NewGracefulLimiter(amount int, frequency time.Duration, grace time.Duration) Limiter { | ||||||
|  | 	return &simpleLimiter{ | ||||||
|  | 		Amount:    amount, | ||||||
|  | 		Frequency: frequency, | ||||||
|  | 		numRead:   minInt, | ||||||
|  | 		timeRead:  time.Now().Add(grace), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Count applies n bytes to the limiter. | ||||||
|  | func (limit *simpleLimiter) Count(n int) error { | ||||||
|  | 	now := time.Now() | ||||||
|  | 	if now.After(limit.timeRead) { | ||||||
|  | 		limit.numRead = 0 | ||||||
|  | 		limit.timeRead = now.Add(limit.Frequency) | ||||||
|  | 	} | ||||||
|  | 	limit.numRead += n | ||||||
|  | 	if limit.numRead > limit.Amount { | ||||||
|  | 		return ErrRateExceeded | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								vendor/github.com/shazow/rateio/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/shazow/rateio/reader.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | package rateio | ||||||
|  |  | ||||||
|  | import "io" | ||||||
|  |  | ||||||
|  | type reader struct { | ||||||
|  | 	io.Reader | ||||||
|  | 	Limiter | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Read reads data into p. | ||||||
|  | // Returns ErrRateExceeded error if our specified read is exceeded. | ||||||
|  | func (r *reader) Read(p []byte) (n int, err error) { | ||||||
|  | 	n, err = r.Reader.Read(p) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = r.Limiter.Count(n) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewReader proxies an io.Reader but keeps track of bytes read based on our Limiter. | ||||||
|  | func NewReader(r io.Reader, limiter Limiter) io.Reader { | ||||||
|  | 	return &reader{r, limiter} | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								vendor/github.com/shazow/rateio/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/shazow/rateio/writer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | package rateio | ||||||
|  |  | ||||||
|  | import "io" | ||||||
|  |  | ||||||
|  | type writer struct { | ||||||
|  | 	io.Writer | ||||||
|  | 	Limiter | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Write writes the contents of p into the buffer. | ||||||
|  | // Returns ErrRateExceeded error if our specified read is exceeded. | ||||||
|  | func (w *writer) Write(p []byte) (n int, err error) { | ||||||
|  | 	n, err = w.Writer.Write(p) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = w.Limiter.Count(n) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewWriter proxies an io.Writer but keeps track of bytes read based on our Limiter. | ||||||
|  | func NewWriter(w io.Writer, limiter Limiter) io.Writer { | ||||||
|  | 	return &writer{w, limiter} | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								vendor/github.com/shazow/ssh-chat/sshd/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/shazow/ssh-chat/sshd/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | The MIT License (MIT) | ||||||
|  |  | ||||||
|  | Copyright (c) 2014 Andrey Petrov | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in all | ||||||
|  | copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  | SOFTWARE. | ||||||
							
								
								
									
										72
									
								
								vendor/github.com/shazow/ssh-chat/sshd/auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								vendor/github.com/shazow/ssh-chat/sshd/auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | package sshd | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"crypto/sha256" | ||||||
|  | 	"encoding/base64" | ||||||
|  | 	"errors" | ||||||
|  | 	"net" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/crypto/ssh" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Auth is used to authenticate connections based on public keys. | ||||||
|  | type Auth interface { | ||||||
|  | 	// Whether to allow connections without a public key. | ||||||
|  | 	AllowAnonymous() bool | ||||||
|  | 	// Given address and public key, return if the connection should be permitted. | ||||||
|  | 	Check(net.Addr, ssh.PublicKey) (bool, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MakeAuth makes an ssh.ServerConfig which performs authentication against an Auth implementation. | ||||||
|  | func MakeAuth(auth Auth) *ssh.ServerConfig { | ||||||
|  | 	config := ssh.ServerConfig{ | ||||||
|  | 		NoClientAuth: false, | ||||||
|  | 		// Auth-related things should be constant-time to avoid timing attacks. | ||||||
|  | 		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { | ||||||
|  | 			ok, err := auth.Check(conn.RemoteAddr(), key) | ||||||
|  | 			if !ok { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  | 			perm := &ssh.Permissions{Extensions: map[string]string{ | ||||||
|  | 				"pubkey": string(key.Marshal()), | ||||||
|  | 			}} | ||||||
|  | 			return perm, nil | ||||||
|  | 		}, | ||||||
|  | 		KeyboardInteractiveCallback: func(conn ssh.ConnMetadata, challenge ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) { | ||||||
|  | 			if !auth.AllowAnonymous() { | ||||||
|  | 				return nil, errors.New("public key authentication required") | ||||||
|  | 			} | ||||||
|  | 			_, err := auth.Check(conn.RemoteAddr(), nil) | ||||||
|  | 			return nil, err | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &config | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MakeNoAuth makes a simple ssh.ServerConfig which allows all connections. | ||||||
|  | // Primarily used for testing. | ||||||
|  | func MakeNoAuth() *ssh.ServerConfig { | ||||||
|  | 	config := ssh.ServerConfig{ | ||||||
|  | 		NoClientAuth: false, | ||||||
|  | 		// Auth-related things should be constant-time to avoid timing attacks. | ||||||
|  | 		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { | ||||||
|  | 			perm := &ssh.Permissions{Extensions: map[string]string{ | ||||||
|  | 				"pubkey": string(key.Marshal()), | ||||||
|  | 			}} | ||||||
|  | 			return perm, nil | ||||||
|  | 		}, | ||||||
|  | 		KeyboardInteractiveCallback: func(conn ssh.ConnMetadata, challenge ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) { | ||||||
|  | 			return nil, nil | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &config | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Fingerprint performs a SHA256 BASE64 fingerprint of the PublicKey, similar to OpenSSH. | ||||||
|  | // See: https://anongit.mindrot.org/openssh.git/commit/?id=56d1c83cdd1ac | ||||||
|  | func Fingerprint(k ssh.PublicKey) string { | ||||||
|  | 	hash := sha256.Sum256(k.Marshal()) | ||||||
|  | 	return "SHA256:" + base64.StdEncoding.EncodeToString(hash[:]) | ||||||
|  | } | ||||||
							
								
								
									
										76
									
								
								vendor/github.com/shazow/ssh-chat/sshd/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								vendor/github.com/shazow/ssh-chat/sshd/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | package sshd | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"crypto/rsa" | ||||||
|  | 	"io" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/crypto/ssh" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // NewRandomSigner generates a random key of a desired bit length. | ||||||
|  | func NewRandomSigner(bits int) (ssh.Signer, error) { | ||||||
|  | 	key, err := rsa.GenerateKey(rand.Reader, bits) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return ssh.NewSignerFromKey(key) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewClientConfig creates a barebones ssh.ClientConfig to be used with ssh.Dial. | ||||||
|  | func NewClientConfig(name string) *ssh.ClientConfig { | ||||||
|  | 	return &ssh.ClientConfig{ | ||||||
|  | 		User: name, | ||||||
|  | 		Auth: []ssh.AuthMethod{ | ||||||
|  | 			ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (answers []string, err error) { | ||||||
|  | 				return | ||||||
|  | 			}), | ||||||
|  | 		}, | ||||||
|  | 		HostKeyCallback: ssh.InsecureIgnoreHostKey(), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ConnectShell makes a barebones SSH client session, used for testing. | ||||||
|  | func ConnectShell(host string, name string, handler func(r io.Reader, w io.WriteCloser) error) error { | ||||||
|  | 	config := NewClientConfig(name) | ||||||
|  | 	conn, err := ssh.Dial("tcp", host, config) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer conn.Close() | ||||||
|  |  | ||||||
|  | 	session, err := conn.NewSession() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer session.Close() | ||||||
|  |  | ||||||
|  | 	in, err := session.StdinPipe() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	out, err := session.StdoutPipe() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 		err = session.RequestPty("xterm", 80, 40, ssh.TerminalModes{}) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	*/ | ||||||
|  |  | ||||||
|  | 	err = session.Shell() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	_, err = session.SendRequest("ping", true, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return handler(out, in) | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								vendor/github.com/shazow/ssh-chat/sshd/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/shazow/ssh-chat/sshd/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | package sshd | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  | ||||||
|  | 	signer, err := ssh.ParsePrivateKey(privateKey) | ||||||
|  |  | ||||||
|  | 	config := MakeNoAuth() | ||||||
|  | 	config.AddHostKey(signer) | ||||||
|  |  | ||||||
|  | 	s, err := ListenSSH("0.0.0.0:2022", config) | ||||||
|  | 	if err != nil { | ||||||
|  | 		// Handle opening socket error | ||||||
|  | 	} | ||||||
|  | 	defer s.Close() | ||||||
|  |  | ||||||
|  | 	terminals := s.ServeTerminal() | ||||||
|  |  | ||||||
|  | 	for term := range terminals { | ||||||
|  | 		go func() { | ||||||
|  | 			defer term.Close() | ||||||
|  | 			term.SetPrompt("...") | ||||||
|  | 			term.AutoCompleteCallback = nil // ... | ||||||
|  |  | ||||||
|  | 			for { | ||||||
|  | 				line, err := term.ReadLine() | ||||||
|  | 				if err != nil { | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 				term.Write(...) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		}() | ||||||
|  | 	} | ||||||
|  | */ | ||||||
							
								
								
									
										22
									
								
								vendor/github.com/shazow/ssh-chat/sshd/logger.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/shazow/ssh-chat/sshd/logger.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | package sshd | ||||||
|  |  | ||||||
|  | import "io" | ||||||
|  | import stdlog "log" | ||||||
|  |  | ||||||
|  | var logger *stdlog.Logger | ||||||
|  |  | ||||||
|  | func SetLogger(w io.Writer) { | ||||||
|  | 	flags := stdlog.Flags() | ||||||
|  | 	prefix := "[sshd] " | ||||||
|  | 	logger = stdlog.New(w, prefix, flags) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type nullWriter struct{} | ||||||
|  |  | ||||||
|  | func (nullWriter) Write(data []byte) (int, error) { | ||||||
|  | 	return len(data), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	SetLogger(nullWriter{}) | ||||||
|  | } | ||||||
							
								
								
									
										67
									
								
								vendor/github.com/shazow/ssh-chat/sshd/net.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								vendor/github.com/shazow/ssh-chat/sshd/net.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | |||||||
|  | package sshd | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"net" | ||||||
|  |  | ||||||
|  | 	"github.com/shazow/rateio" | ||||||
|  | 	"golang.org/x/crypto/ssh" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Container for the connection and ssh-related configuration | ||||||
|  | type SSHListener struct { | ||||||
|  | 	net.Listener | ||||||
|  | 	config *ssh.ServerConfig | ||||||
|  |  | ||||||
|  | 	RateLimit   func() rateio.Limiter | ||||||
|  | 	HandlerFunc func(term *Terminal) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Make an SSH listener socket | ||||||
|  | func ListenSSH(laddr string, config *ssh.ServerConfig) (*SSHListener, error) { | ||||||
|  | 	socket, err := net.Listen("tcp", laddr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	l := SSHListener{Listener: socket, config: config} | ||||||
|  | 	return &l, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *SSHListener) handleConn(conn net.Conn) (*Terminal, error) { | ||||||
|  | 	if l.RateLimit != nil { | ||||||
|  | 		// TODO: Configurable Limiter? | ||||||
|  | 		conn = ReadLimitConn(conn, l.RateLimit()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Upgrade TCP connection to SSH connection | ||||||
|  | 	sshConn, channels, requests, err := ssh.NewServerConn(conn, l.config) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// FIXME: Disconnect if too many faulty requests? (Avoid DoS.) | ||||||
|  | 	go ssh.DiscardRequests(requests) | ||||||
|  | 	return NewSession(sshConn, channels) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Accept incoming connections as terminal requests and yield them | ||||||
|  | func (l *SSHListener) Serve() { | ||||||
|  | 	defer l.Close() | ||||||
|  | 	for { | ||||||
|  | 		conn, err := l.Accept() | ||||||
|  |  | ||||||
|  | 		if err != nil { | ||||||
|  | 			logger.Printf("Failed to accept connection: %s", err) | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Goroutineify to resume accepting sockets early | ||||||
|  | 		go func() { | ||||||
|  | 			term, err := l.handleConn(conn) | ||||||
|  | 			if err != nil { | ||||||
|  | 				logger.Printf("[%s] Failed to handshake: %s", conn.RemoteAddr(), err) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			l.HandlerFunc(term) | ||||||
|  | 		}() | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										70
									
								
								vendor/github.com/shazow/ssh-chat/sshd/pty.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								vendor/github.com/shazow/ssh-chat/sshd/pty.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | |||||||
|  | package sshd | ||||||
|  |  | ||||||
|  | import "encoding/binary" | ||||||
|  |  | ||||||
|  | // Helpers below are borrowed from go.crypto circa 2011: | ||||||
|  |  | ||||||
|  | // parsePtyRequest parses the payload of the pty-req message and extracts the | ||||||
|  | // dimensions of the terminal. See RFC 4254, section 6.2. | ||||||
|  | func parsePtyRequest(s []byte) (width, height int, ok bool) { | ||||||
|  | 	_, s, ok = parseString(s) | ||||||
|  | 	if !ok { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	width32, s, ok := parseUint32(s) | ||||||
|  | 	if !ok { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	height32, _, ok := parseUint32(s) | ||||||
|  | 	width = int(width32) | ||||||
|  | 	height = int(height32) | ||||||
|  | 	if width < 1 { | ||||||
|  | 		ok = false | ||||||
|  | 	} | ||||||
|  | 	if height < 1 { | ||||||
|  | 		ok = false | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseWinchRequest(s []byte) (width, height int, ok bool) { | ||||||
|  | 	width32, _, ok := parseUint32(s) | ||||||
|  | 	if !ok { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	height32, _, ok := parseUint32(s) | ||||||
|  | 	if !ok { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	width = int(width32) | ||||||
|  | 	height = int(height32) | ||||||
|  | 	if width < 1 { | ||||||
|  | 		ok = false | ||||||
|  | 	} | ||||||
|  | 	if height < 1 { | ||||||
|  | 		ok = false | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseString(in []byte) (out string, rest []byte, ok bool) { | ||||||
|  | 	if len(in) < 4 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	length := binary.BigEndian.Uint32(in) | ||||||
|  | 	if uint32(len(in)) < 4+length { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	out = string(in[4 : 4+length]) | ||||||
|  | 	rest = in[4+length:] | ||||||
|  | 	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 | ||||||
|  | } | ||||||
							
								
								
									
										71
									
								
								vendor/github.com/shazow/ssh-chat/sshd/ratelimit.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/shazow/ssh-chat/sshd/ratelimit.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | package sshd | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"io" | ||||||
|  | 	"net" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/shazow/rateio" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type limitedConn struct { | ||||||
|  | 	net.Conn | ||||||
|  | 	io.Reader // Our rate-limited io.Reader for net.Conn | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *limitedConn) Read(p []byte) (n int, err error) { | ||||||
|  | 	return r.Reader.Read(p) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ReadLimitConn returns a net.Conn whose io.Reader interface is rate-limited by limiter. | ||||||
|  | func ReadLimitConn(conn net.Conn, limiter rateio.Limiter) net.Conn { | ||||||
|  | 	return &limitedConn{ | ||||||
|  | 		Conn:   conn, | ||||||
|  | 		Reader: rateio.NewReader(conn, limiter), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Count each read as 1 unless it exceeds some number of bytes. | ||||||
|  | type inputLimiter struct { | ||||||
|  | 	// TODO: Could do all kinds of fancy things here, like be more forgiving of | ||||||
|  | 	// connections that have been around for a while. | ||||||
|  |  | ||||||
|  | 	Amount    int | ||||||
|  | 	Frequency time.Duration | ||||||
|  |  | ||||||
|  | 	remaining int | ||||||
|  | 	readCap   int | ||||||
|  | 	numRead   int | ||||||
|  | 	timeRead  time.Time | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewInputLimiter returns a rateio.Limiter with sensible defaults for | ||||||
|  | // differentiating between humans typing and bots spamming. | ||||||
|  | func NewInputLimiter() rateio.Limiter { | ||||||
|  | 	grace := time.Second * 3 | ||||||
|  | 	return &inputLimiter{ | ||||||
|  | 		Amount:    2 << 14, // ~16kb, should be plenty for a high typing rate/copypasta/large key handshakes. | ||||||
|  | 		Frequency: time.Minute * 1, | ||||||
|  | 		readCap:   128,          // Allow up to 128 bytes per read (anecdotally, 1 character = 52 bytes over ssh) | ||||||
|  | 		numRead:   -1024 * 1024, // Start with a 1mb grace | ||||||
|  | 		timeRead:  time.Now().Add(grace), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Count applies 1 if n<readCap, else n | ||||||
|  | func (limit *inputLimiter) Count(n int) error { | ||||||
|  | 	now := time.Now() | ||||||
|  | 	if now.After(limit.timeRead) { | ||||||
|  | 		limit.numRead = 0 | ||||||
|  | 		limit.timeRead = now.Add(limit.Frequency) | ||||||
|  | 	} | ||||||
|  | 	if n <= limit.readCap { | ||||||
|  | 		limit.numRead += 1 | ||||||
|  | 	} else { | ||||||
|  | 		limit.numRead += n | ||||||
|  | 	} | ||||||
|  | 	if limit.numRead > limit.Amount { | ||||||
|  | 		return rateio.ErrRateExceeded | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										167
									
								
								vendor/github.com/shazow/ssh-chat/sshd/terminal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								vendor/github.com/shazow/ssh-chat/sshd/terminal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | |||||||
|  | package sshd | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"net" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/crypto/ssh" | ||||||
|  | 	"golang.org/x/crypto/ssh/terminal" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var keepaliveInterval = time.Second * 30 | ||||||
|  | var keepaliveRequest = "keepalive@ssh-chat" | ||||||
|  |  | ||||||
|  | var ErrNoSessionChannel = errors.New("no session channel") | ||||||
|  | var ErrNotSessionChannel = errors.New("terminal requires session channel") | ||||||
|  |  | ||||||
|  | // Connection is an interface with fields necessary to operate an sshd host. | ||||||
|  | type Connection interface { | ||||||
|  | 	PublicKey() ssh.PublicKey | ||||||
|  | 	RemoteAddr() net.Addr | ||||||
|  | 	Name() string | ||||||
|  | 	ClientVersion() []byte | ||||||
|  | 	Close() error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type sshConn struct { | ||||||
|  | 	*ssh.ServerConn | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c sshConn) PublicKey() ssh.PublicKey { | ||||||
|  | 	if c.Permissions == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	s, ok := c.Permissions.Extensions["pubkey"] | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	key, err := ssh.ParsePublicKey([]byte(s)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return key | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c sshConn) Name() string { | ||||||
|  | 	return c.User() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Extending ssh/terminal to include a closer interface | ||||||
|  | type Terminal struct { | ||||||
|  | 	terminal.Terminal | ||||||
|  | 	Conn    Connection | ||||||
|  | 	Channel ssh.Channel | ||||||
|  |  | ||||||
|  | 	done      chan struct{} | ||||||
|  | 	closeOnce sync.Once | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Make new terminal from a session channel | ||||||
|  | func NewTerminal(conn *ssh.ServerConn, ch ssh.NewChannel) (*Terminal, error) { | ||||||
|  | 	if ch.ChannelType() != "session" { | ||||||
|  | 		return nil, ErrNotSessionChannel | ||||||
|  | 	} | ||||||
|  | 	channel, requests, err := ch.Accept() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	term := Terminal{ | ||||||
|  | 		Terminal: *terminal.NewTerminal(channel, "Connecting..."), | ||||||
|  | 		Conn:     sshConn{conn}, | ||||||
|  | 		Channel:  channel, | ||||||
|  |  | ||||||
|  | 		done: make(chan struct{}), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	go term.listen(requests) | ||||||
|  |  | ||||||
|  | 	go func() { | ||||||
|  | 		// Keep-Alive Ticker | ||||||
|  | 		ticker := time.Tick(keepaliveInterval) | ||||||
|  | 		for { | ||||||
|  | 			select { | ||||||
|  | 			case <-ticker: | ||||||
|  | 				_, err := channel.SendRequest(keepaliveRequest, true, nil) | ||||||
|  | 				if err != nil { | ||||||
|  | 					// Connection is gone | ||||||
|  | 					logger.Printf("[%s] Keepalive failed, closing terminal: %s", term.Conn.RemoteAddr(), err) | ||||||
|  | 					term.Close() | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
|  | 			case <-term.done: | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	return &term, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Find session channel and make a Terminal from it | ||||||
|  | func NewSession(conn *ssh.ServerConn, channels <-chan ssh.NewChannel) (*Terminal, error) { | ||||||
|  | 	// Make a terminal from the first session found | ||||||
|  | 	for ch := range channels { | ||||||
|  | 		if t := ch.ChannelType(); t != "session" { | ||||||
|  | 			logger.Printf("[%s] Ignored channel type: %s", conn.RemoteAddr(), t) | ||||||
|  | 			ch.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t)) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return NewTerminal(conn, ch) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil, ErrNoSessionChannel | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close terminal and ssh connection | ||||||
|  | func (t *Terminal) Close() error { | ||||||
|  | 	var err error | ||||||
|  | 	t.closeOnce.Do(func() { | ||||||
|  | 		close(t.done) | ||||||
|  | 		t.Channel.Close() | ||||||
|  | 		err = t.Conn.Close() | ||||||
|  | 	}) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Negotiate terminal type and settings | ||||||
|  | func (t *Terminal) listen(requests <-chan *ssh.Request) { | ||||||
|  | 	hasShell := false | ||||||
|  |  | ||||||
|  | 	for req := range requests { | ||||||
|  | 		var width, height int | ||||||
|  | 		var ok bool | ||||||
|  |  | ||||||
|  | 		switch req.Type { | ||||||
|  | 		case "shell": | ||||||
|  | 			if !hasShell { | ||||||
|  | 				ok = true | ||||||
|  | 				hasShell = true | ||||||
|  | 			} | ||||||
|  | 		case "pty-req": | ||||||
|  | 			width, height, ok = parsePtyRequest(req.Payload) | ||||||
|  | 			if ok { | ||||||
|  | 				// TODO: Hardcode width to 100000? | ||||||
|  | 				err := t.SetSize(width, height) | ||||||
|  | 				ok = err == nil | ||||||
|  | 			} | ||||||
|  | 		case "window-change": | ||||||
|  | 			width, height, ok = parseWinchRequest(req.Payload) | ||||||
|  | 			if ok { | ||||||
|  | 				// TODO: Hardcode width to 100000? | ||||||
|  | 				err := t.SetSize(width, height) | ||||||
|  | 				ok = err == nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if req.WantReply { | ||||||
|  | 			req.Reply(ok, nil) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								vendor/golang.org/x/crypto/curve25519/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/golang.org/x/crypto/curve25519/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | Copyright (c) 2009 The Go Authors. All rights reserved. | ||||||
|  |  | ||||||
|  | Redistribution and use in source and binary forms, with or without | ||||||
|  | modification, are permitted provided that the following conditions are | ||||||
|  | met: | ||||||
|  |  | ||||||
|  |    * Redistributions of source code must retain the above copyright | ||||||
|  | notice, this list of conditions and the following disclaimer. | ||||||
|  |    * Redistributions in binary form must reproduce the above | ||||||
|  | copyright notice, this list of conditions and the following disclaimer | ||||||
|  | in the documentation and/or other materials provided with the | ||||||
|  | distribution. | ||||||
|  |    * Neither the name of Google Inc. nor the names of its | ||||||
|  | contributors may be used to endorse or promote products derived from | ||||||
|  | this software without specific prior written permission. | ||||||
|  |  | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
							
								
								
									
										8
									
								
								vendor/golang.org/x/crypto/curve25519/const_amd64.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/golang.org/x/crypto/curve25519/const_amd64.h
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | // Copyright 2012 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. | ||||||
|  |  | ||||||
|  | // This code was translated into a form compatible with 6a from the public | ||||||
|  | // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | ||||||
|  |  | ||||||
|  | #define REDMASK51     0x0007FFFFFFFFFFFF | ||||||
							
								
								
									
										20
									
								
								vendor/golang.org/x/crypto/curve25519/const_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/golang.org/x/crypto/curve25519/const_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | // Copyright 2012 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. | ||||||
|  |  | ||||||
|  | // This code was translated into a form compatible with 6a from the public | ||||||
|  | // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | ||||||
|  |  | ||||||
|  | // +build amd64,!gccgo,!appengine | ||||||
|  |  | ||||||
|  | // These constants cannot be encoded in non-MOVQ immediates. | ||||||
|  | // We access them directly from memory instead. | ||||||
|  |  | ||||||
|  | DATA ·_121666_213(SB)/8, $996687872 | ||||||
|  | GLOBL ·_121666_213(SB), 8, $8 | ||||||
|  |  | ||||||
|  | DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA | ||||||
|  | GLOBL ·_2P0(SB), 8, $8 | ||||||
|  |  | ||||||
|  | DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE | ||||||
|  | GLOBL ·_2P1234(SB), 8, $8 | ||||||
							
								
								
									
										65
									
								
								vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | |||||||
|  | // Copyright 2012 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. | ||||||
|  |  | ||||||
|  | // +build amd64,!gccgo,!appengine | ||||||
|  |  | ||||||
|  | // func cswap(inout *[4][5]uint64, v uint64) | ||||||
|  | TEXT ·cswap(SB),7,$0 | ||||||
|  | 	MOVQ inout+0(FP),DI | ||||||
|  | 	MOVQ v+8(FP),SI | ||||||
|  |  | ||||||
|  | 	SUBQ $1, SI | ||||||
|  | 	NOTQ SI | ||||||
|  | 	MOVQ SI, X15 | ||||||
|  | 	PSHUFD $0x44, X15, X15 | ||||||
|  |  | ||||||
|  | 	MOVOU 0(DI), X0 | ||||||
|  | 	MOVOU 16(DI), X2 | ||||||
|  | 	MOVOU 32(DI), X4 | ||||||
|  | 	MOVOU 48(DI), X6 | ||||||
|  | 	MOVOU 64(DI), X8 | ||||||
|  | 	MOVOU 80(DI), X1 | ||||||
|  | 	MOVOU 96(DI), X3 | ||||||
|  | 	MOVOU 112(DI), X5 | ||||||
|  | 	MOVOU 128(DI), X7 | ||||||
|  | 	MOVOU 144(DI), X9 | ||||||
|  |  | ||||||
|  | 	MOVO X1, X10 | ||||||
|  | 	MOVO X3, X11 | ||||||
|  | 	MOVO X5, X12 | ||||||
|  | 	MOVO X7, X13 | ||||||
|  | 	MOVO X9, X14 | ||||||
|  |  | ||||||
|  | 	PXOR X0, X10 | ||||||
|  | 	PXOR X2, X11 | ||||||
|  | 	PXOR X4, X12 | ||||||
|  | 	PXOR X6, X13 | ||||||
|  | 	PXOR X8, X14 | ||||||
|  | 	PAND X15, X10 | ||||||
|  | 	PAND X15, X11 | ||||||
|  | 	PAND X15, X12 | ||||||
|  | 	PAND X15, X13 | ||||||
|  | 	PAND X15, X14 | ||||||
|  | 	PXOR X10, X0 | ||||||
|  | 	PXOR X10, X1 | ||||||
|  | 	PXOR X11, X2 | ||||||
|  | 	PXOR X11, X3 | ||||||
|  | 	PXOR X12, X4 | ||||||
|  | 	PXOR X12, X5 | ||||||
|  | 	PXOR X13, X6 | ||||||
|  | 	PXOR X13, X7 | ||||||
|  | 	PXOR X14, X8 | ||||||
|  | 	PXOR X14, X9 | ||||||
|  |  | ||||||
|  | 	MOVOU X0, 0(DI) | ||||||
|  | 	MOVOU X2, 16(DI) | ||||||
|  | 	MOVOU X4, 32(DI) | ||||||
|  | 	MOVOU X6, 48(DI) | ||||||
|  | 	MOVOU X8, 64(DI) | ||||||
|  | 	MOVOU X1, 80(DI) | ||||||
|  | 	MOVOU X3, 96(DI) | ||||||
|  | 	MOVOU X5, 112(DI) | ||||||
|  | 	MOVOU X7, 128(DI) | ||||||
|  | 	MOVOU X9, 144(DI) | ||||||
|  | 	RET | ||||||
							
								
								
									
										834
									
								
								vendor/golang.org/x/crypto/curve25519/curve25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										834
									
								
								vendor/golang.org/x/crypto/curve25519/curve25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,834 @@ | |||||||
|  | // Copyright 2013 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. | ||||||
|  |  | ||||||
|  | // We have an implementation in amd64 assembly so this code is only run on | ||||||
|  | // non-amd64 platforms. The amd64 assembly does not support gccgo. | ||||||
|  | // +build !amd64 gccgo appengine | ||||||
|  |  | ||||||
|  | package curve25519 | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/binary" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // This code is a port of the public domain, "ref10" implementation of | ||||||
|  | // curve25519 from SUPERCOP 20130419 by D. J. Bernstein. | ||||||
|  |  | ||||||
|  | // fieldElement represents an element of the field GF(2^255 - 19). An element | ||||||
|  | // t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77 | ||||||
|  | // t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on | ||||||
|  | // context. | ||||||
|  | type fieldElement [10]int32 | ||||||
|  |  | ||||||
|  | func feZero(fe *fieldElement) { | ||||||
|  | 	for i := range fe { | ||||||
|  | 		fe[i] = 0 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func feOne(fe *fieldElement) { | ||||||
|  | 	feZero(fe) | ||||||
|  | 	fe[0] = 1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func feAdd(dst, a, b *fieldElement) { | ||||||
|  | 	for i := range dst { | ||||||
|  | 		dst[i] = a[i] + b[i] | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func feSub(dst, a, b *fieldElement) { | ||||||
|  | 	for i := range dst { | ||||||
|  | 		dst[i] = a[i] - b[i] | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func feCopy(dst, src *fieldElement) { | ||||||
|  | 	for i := range dst { | ||||||
|  | 		dst[i] = src[i] | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0. | ||||||
|  | // | ||||||
|  | // Preconditions: b in {0,1}. | ||||||
|  | func feCSwap(f, g *fieldElement, b int32) { | ||||||
|  | 	b = -b | ||||||
|  | 	for i := range f { | ||||||
|  | 		t := b & (f[i] ^ g[i]) | ||||||
|  | 		f[i] ^= t | ||||||
|  | 		g[i] ^= t | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // load3 reads a 24-bit, little-endian value from in. | ||||||
|  | func load3(in []byte) int64 { | ||||||
|  | 	var r int64 | ||||||
|  | 	r = int64(in[0]) | ||||||
|  | 	r |= int64(in[1]) << 8 | ||||||
|  | 	r |= int64(in[2]) << 16 | ||||||
|  | 	return r | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // load4 reads a 32-bit, little-endian value from in. | ||||||
|  | func load4(in []byte) int64 { | ||||||
|  | 	return int64(binary.LittleEndian.Uint32(in)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func feFromBytes(dst *fieldElement, src *[32]byte) { | ||||||
|  | 	h0 := load4(src[:]) | ||||||
|  | 	h1 := load3(src[4:]) << 6 | ||||||
|  | 	h2 := load3(src[7:]) << 5 | ||||||
|  | 	h3 := load3(src[10:]) << 3 | ||||||
|  | 	h4 := load3(src[13:]) << 2 | ||||||
|  | 	h5 := load4(src[16:]) | ||||||
|  | 	h6 := load3(src[20:]) << 7 | ||||||
|  | 	h7 := load3(src[23:]) << 5 | ||||||
|  | 	h8 := load3(src[26:]) << 4 | ||||||
|  | 	h9 := load3(src[29:]) << 2 | ||||||
|  |  | ||||||
|  | 	var carry [10]int64 | ||||||
|  | 	carry[9] = (h9 + 1<<24) >> 25 | ||||||
|  | 	h0 += carry[9] * 19 | ||||||
|  | 	h9 -= carry[9] << 25 | ||||||
|  | 	carry[1] = (h1 + 1<<24) >> 25 | ||||||
|  | 	h2 += carry[1] | ||||||
|  | 	h1 -= carry[1] << 25 | ||||||
|  | 	carry[3] = (h3 + 1<<24) >> 25 | ||||||
|  | 	h4 += carry[3] | ||||||
|  | 	h3 -= carry[3] << 25 | ||||||
|  | 	carry[5] = (h5 + 1<<24) >> 25 | ||||||
|  | 	h6 += carry[5] | ||||||
|  | 	h5 -= carry[5] << 25 | ||||||
|  | 	carry[7] = (h7 + 1<<24) >> 25 | ||||||
|  | 	h8 += carry[7] | ||||||
|  | 	h7 -= carry[7] << 25 | ||||||
|  |  | ||||||
|  | 	carry[0] = (h0 + 1<<25) >> 26 | ||||||
|  | 	h1 += carry[0] | ||||||
|  | 	h0 -= carry[0] << 26 | ||||||
|  | 	carry[2] = (h2 + 1<<25) >> 26 | ||||||
|  | 	h3 += carry[2] | ||||||
|  | 	h2 -= carry[2] << 26 | ||||||
|  | 	carry[4] = (h4 + 1<<25) >> 26 | ||||||
|  | 	h5 += carry[4] | ||||||
|  | 	h4 -= carry[4] << 26 | ||||||
|  | 	carry[6] = (h6 + 1<<25) >> 26 | ||||||
|  | 	h7 += carry[6] | ||||||
|  | 	h6 -= carry[6] << 26 | ||||||
|  | 	carry[8] = (h8 + 1<<25) >> 26 | ||||||
|  | 	h9 += carry[8] | ||||||
|  | 	h8 -= carry[8] << 26 | ||||||
|  |  | ||||||
|  | 	dst[0] = int32(h0) | ||||||
|  | 	dst[1] = int32(h1) | ||||||
|  | 	dst[2] = int32(h2) | ||||||
|  | 	dst[3] = int32(h3) | ||||||
|  | 	dst[4] = int32(h4) | ||||||
|  | 	dst[5] = int32(h5) | ||||||
|  | 	dst[6] = int32(h6) | ||||||
|  | 	dst[7] = int32(h7) | ||||||
|  | 	dst[8] = int32(h8) | ||||||
|  | 	dst[9] = int32(h9) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // feToBytes marshals h to s. | ||||||
|  | // Preconditions: | ||||||
|  | //   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | ||||||
|  | // | ||||||
|  | // Write p=2^255-19; q=floor(h/p). | ||||||
|  | // Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). | ||||||
|  | // | ||||||
|  | // Proof: | ||||||
|  | //   Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. | ||||||
|  | //   Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4. | ||||||
|  | // | ||||||
|  | //   Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). | ||||||
|  | //   Then 0<y<1. | ||||||
|  | // | ||||||
|  | //   Write r=h-pq. | ||||||
|  | //   Have 0<=r<=p-1=2^255-20. | ||||||
|  | //   Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1. | ||||||
|  | // | ||||||
|  | //   Write x=r+19(2^-255)r+y. | ||||||
|  | //   Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q. | ||||||
|  | // | ||||||
|  | //   Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1)) | ||||||
|  | //   so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q. | ||||||
|  | func feToBytes(s *[32]byte, h *fieldElement) { | ||||||
|  | 	var carry [10]int32 | ||||||
|  |  | ||||||
|  | 	q := (19*h[9] + (1 << 24)) >> 25 | ||||||
|  | 	q = (h[0] + q) >> 26 | ||||||
|  | 	q = (h[1] + q) >> 25 | ||||||
|  | 	q = (h[2] + q) >> 26 | ||||||
|  | 	q = (h[3] + q) >> 25 | ||||||
|  | 	q = (h[4] + q) >> 26 | ||||||
|  | 	q = (h[5] + q) >> 25 | ||||||
|  | 	q = (h[6] + q) >> 26 | ||||||
|  | 	q = (h[7] + q) >> 25 | ||||||
|  | 	q = (h[8] + q) >> 26 | ||||||
|  | 	q = (h[9] + q) >> 25 | ||||||
|  |  | ||||||
|  | 	// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. | ||||||
|  | 	h[0] += 19 * q | ||||||
|  | 	// Goal: Output h-2^255 q, which is between 0 and 2^255-20. | ||||||
|  |  | ||||||
|  | 	carry[0] = h[0] >> 26 | ||||||
|  | 	h[1] += carry[0] | ||||||
|  | 	h[0] -= carry[0] << 26 | ||||||
|  | 	carry[1] = h[1] >> 25 | ||||||
|  | 	h[2] += carry[1] | ||||||
|  | 	h[1] -= carry[1] << 25 | ||||||
|  | 	carry[2] = h[2] >> 26 | ||||||
|  | 	h[3] += carry[2] | ||||||
|  | 	h[2] -= carry[2] << 26 | ||||||
|  | 	carry[3] = h[3] >> 25 | ||||||
|  | 	h[4] += carry[3] | ||||||
|  | 	h[3] -= carry[3] << 25 | ||||||
|  | 	carry[4] = h[4] >> 26 | ||||||
|  | 	h[5] += carry[4] | ||||||
|  | 	h[4] -= carry[4] << 26 | ||||||
|  | 	carry[5] = h[5] >> 25 | ||||||
|  | 	h[6] += carry[5] | ||||||
|  | 	h[5] -= carry[5] << 25 | ||||||
|  | 	carry[6] = h[6] >> 26 | ||||||
|  | 	h[7] += carry[6] | ||||||
|  | 	h[6] -= carry[6] << 26 | ||||||
|  | 	carry[7] = h[7] >> 25 | ||||||
|  | 	h[8] += carry[7] | ||||||
|  | 	h[7] -= carry[7] << 25 | ||||||
|  | 	carry[8] = h[8] >> 26 | ||||||
|  | 	h[9] += carry[8] | ||||||
|  | 	h[8] -= carry[8] << 26 | ||||||
|  | 	carry[9] = h[9] >> 25 | ||||||
|  | 	h[9] -= carry[9] << 25 | ||||||
|  | 	// h10 = carry9 | ||||||
|  |  | ||||||
|  | 	// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. | ||||||
|  | 	// Have h[0]+...+2^230 h[9] between 0 and 2^255-1; | ||||||
|  | 	// evidently 2^255 h10-2^255 q = 0. | ||||||
|  | 	// Goal: Output h[0]+...+2^230 h[9]. | ||||||
|  |  | ||||||
|  | 	s[0] = byte(h[0] >> 0) | ||||||
|  | 	s[1] = byte(h[0] >> 8) | ||||||
|  | 	s[2] = byte(h[0] >> 16) | ||||||
|  | 	s[3] = byte((h[0] >> 24) | (h[1] << 2)) | ||||||
|  | 	s[4] = byte(h[1] >> 6) | ||||||
|  | 	s[5] = byte(h[1] >> 14) | ||||||
|  | 	s[6] = byte((h[1] >> 22) | (h[2] << 3)) | ||||||
|  | 	s[7] = byte(h[2] >> 5) | ||||||
|  | 	s[8] = byte(h[2] >> 13) | ||||||
|  | 	s[9] = byte((h[2] >> 21) | (h[3] << 5)) | ||||||
|  | 	s[10] = byte(h[3] >> 3) | ||||||
|  | 	s[11] = byte(h[3] >> 11) | ||||||
|  | 	s[12] = byte((h[3] >> 19) | (h[4] << 6)) | ||||||
|  | 	s[13] = byte(h[4] >> 2) | ||||||
|  | 	s[14] = byte(h[4] >> 10) | ||||||
|  | 	s[15] = byte(h[4] >> 18) | ||||||
|  | 	s[16] = byte(h[5] >> 0) | ||||||
|  | 	s[17] = byte(h[5] >> 8) | ||||||
|  | 	s[18] = byte(h[5] >> 16) | ||||||
|  | 	s[19] = byte((h[5] >> 24) | (h[6] << 1)) | ||||||
|  | 	s[20] = byte(h[6] >> 7) | ||||||
|  | 	s[21] = byte(h[6] >> 15) | ||||||
|  | 	s[22] = byte((h[6] >> 23) | (h[7] << 3)) | ||||||
|  | 	s[23] = byte(h[7] >> 5) | ||||||
|  | 	s[24] = byte(h[7] >> 13) | ||||||
|  | 	s[25] = byte((h[7] >> 21) | (h[8] << 4)) | ||||||
|  | 	s[26] = byte(h[8] >> 4) | ||||||
|  | 	s[27] = byte(h[8] >> 12) | ||||||
|  | 	s[28] = byte((h[8] >> 20) | (h[9] << 6)) | ||||||
|  | 	s[29] = byte(h[9] >> 2) | ||||||
|  | 	s[30] = byte(h[9] >> 10) | ||||||
|  | 	s[31] = byte(h[9] >> 18) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // feMul calculates h = f * g | ||||||
|  | // Can overlap h with f or g. | ||||||
|  | // | ||||||
|  | // Preconditions: | ||||||
|  | //    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | ||||||
|  | //    |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | ||||||
|  | // | ||||||
|  | // Postconditions: | ||||||
|  | //    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | ||||||
|  | // | ||||||
|  | // Notes on implementation strategy: | ||||||
|  | // | ||||||
|  | // Using schoolbook multiplication. | ||||||
|  | // Karatsuba would save a little in some cost models. | ||||||
|  | // | ||||||
|  | // Most multiplications by 2 and 19 are 32-bit precomputations; | ||||||
|  | // cheaper than 64-bit postcomputations. | ||||||
|  | // | ||||||
|  | // There is one remaining multiplication by 19 in the carry chain; | ||||||
|  | // one *19 precomputation can be merged into this, | ||||||
|  | // but the resulting data flow is considerably less clean. | ||||||
|  | // | ||||||
|  | // There are 12 carries below. | ||||||
|  | // 10 of them are 2-way parallelizable and vectorizable. | ||||||
|  | // Can get away with 11 carries, but then data flow is much deeper. | ||||||
|  | // | ||||||
|  | // With tighter constraints on inputs can squeeze carries into int32. | ||||||
|  | func feMul(h, f, g *fieldElement) { | ||||||
|  | 	f0 := f[0] | ||||||
|  | 	f1 := f[1] | ||||||
|  | 	f2 := f[2] | ||||||
|  | 	f3 := f[3] | ||||||
|  | 	f4 := f[4] | ||||||
|  | 	f5 := f[5] | ||||||
|  | 	f6 := f[6] | ||||||
|  | 	f7 := f[7] | ||||||
|  | 	f8 := f[8] | ||||||
|  | 	f9 := f[9] | ||||||
|  | 	g0 := g[0] | ||||||
|  | 	g1 := g[1] | ||||||
|  | 	g2 := g[2] | ||||||
|  | 	g3 := g[3] | ||||||
|  | 	g4 := g[4] | ||||||
|  | 	g5 := g[5] | ||||||
|  | 	g6 := g[6] | ||||||
|  | 	g7 := g[7] | ||||||
|  | 	g8 := g[8] | ||||||
|  | 	g9 := g[9] | ||||||
|  | 	g1_19 := 19 * g1 // 1.4*2^29 | ||||||
|  | 	g2_19 := 19 * g2 // 1.4*2^30; still ok | ||||||
|  | 	g3_19 := 19 * g3 | ||||||
|  | 	g4_19 := 19 * g4 | ||||||
|  | 	g5_19 := 19 * g5 | ||||||
|  | 	g6_19 := 19 * g6 | ||||||
|  | 	g7_19 := 19 * g7 | ||||||
|  | 	g8_19 := 19 * g8 | ||||||
|  | 	g9_19 := 19 * g9 | ||||||
|  | 	f1_2 := 2 * f1 | ||||||
|  | 	f3_2 := 2 * f3 | ||||||
|  | 	f5_2 := 2 * f5 | ||||||
|  | 	f7_2 := 2 * f7 | ||||||
|  | 	f9_2 := 2 * f9 | ||||||
|  | 	f0g0 := int64(f0) * int64(g0) | ||||||
|  | 	f0g1 := int64(f0) * int64(g1) | ||||||
|  | 	f0g2 := int64(f0) * int64(g2) | ||||||
|  | 	f0g3 := int64(f0) * int64(g3) | ||||||
|  | 	f0g4 := int64(f0) * int64(g4) | ||||||
|  | 	f0g5 := int64(f0) * int64(g5) | ||||||
|  | 	f0g6 := int64(f0) * int64(g6) | ||||||
|  | 	f0g7 := int64(f0) * int64(g7) | ||||||
|  | 	f0g8 := int64(f0) * int64(g8) | ||||||
|  | 	f0g9 := int64(f0) * int64(g9) | ||||||
|  | 	f1g0 := int64(f1) * int64(g0) | ||||||
|  | 	f1g1_2 := int64(f1_2) * int64(g1) | ||||||
|  | 	f1g2 := int64(f1) * int64(g2) | ||||||
|  | 	f1g3_2 := int64(f1_2) * int64(g3) | ||||||
|  | 	f1g4 := int64(f1) * int64(g4) | ||||||
|  | 	f1g5_2 := int64(f1_2) * int64(g5) | ||||||
|  | 	f1g6 := int64(f1) * int64(g6) | ||||||
|  | 	f1g7_2 := int64(f1_2) * int64(g7) | ||||||
|  | 	f1g8 := int64(f1) * int64(g8) | ||||||
|  | 	f1g9_38 := int64(f1_2) * int64(g9_19) | ||||||
|  | 	f2g0 := int64(f2) * int64(g0) | ||||||
|  | 	f2g1 := int64(f2) * int64(g1) | ||||||
|  | 	f2g2 := int64(f2) * int64(g2) | ||||||
|  | 	f2g3 := int64(f2) * int64(g3) | ||||||
|  | 	f2g4 := int64(f2) * int64(g4) | ||||||
|  | 	f2g5 := int64(f2) * int64(g5) | ||||||
|  | 	f2g6 := int64(f2) * int64(g6) | ||||||
|  | 	f2g7 := int64(f2) * int64(g7) | ||||||
|  | 	f2g8_19 := int64(f2) * int64(g8_19) | ||||||
|  | 	f2g9_19 := int64(f2) * int64(g9_19) | ||||||
|  | 	f3g0 := int64(f3) * int64(g0) | ||||||
|  | 	f3g1_2 := int64(f3_2) * int64(g1) | ||||||
|  | 	f3g2 := int64(f3) * int64(g2) | ||||||
|  | 	f3g3_2 := int64(f3_2) * int64(g3) | ||||||
|  | 	f3g4 := int64(f3) * int64(g4) | ||||||
|  | 	f3g5_2 := int64(f3_2) * int64(g5) | ||||||
|  | 	f3g6 := int64(f3) * int64(g6) | ||||||
|  | 	f3g7_38 := int64(f3_2) * int64(g7_19) | ||||||
|  | 	f3g8_19 := int64(f3) * int64(g8_19) | ||||||
|  | 	f3g9_38 := int64(f3_2) * int64(g9_19) | ||||||
|  | 	f4g0 := int64(f4) * int64(g0) | ||||||
|  | 	f4g1 := int64(f4) * int64(g1) | ||||||
|  | 	f4g2 := int64(f4) * int64(g2) | ||||||
|  | 	f4g3 := int64(f4) * int64(g3) | ||||||
|  | 	f4g4 := int64(f4) * int64(g4) | ||||||
|  | 	f4g5 := int64(f4) * int64(g5) | ||||||
|  | 	f4g6_19 := int64(f4) * int64(g6_19) | ||||||
|  | 	f4g7_19 := int64(f4) * int64(g7_19) | ||||||
|  | 	f4g8_19 := int64(f4) * int64(g8_19) | ||||||
|  | 	f4g9_19 := int64(f4) * int64(g9_19) | ||||||
|  | 	f5g0 := int64(f5) * int64(g0) | ||||||
|  | 	f5g1_2 := int64(f5_2) * int64(g1) | ||||||
|  | 	f5g2 := int64(f5) * int64(g2) | ||||||
|  | 	f5g3_2 := int64(f5_2) * int64(g3) | ||||||
|  | 	f5g4 := int64(f5) * int64(g4) | ||||||
|  | 	f5g5_38 := int64(f5_2) * int64(g5_19) | ||||||
|  | 	f5g6_19 := int64(f5) * int64(g6_19) | ||||||
|  | 	f5g7_38 := int64(f5_2) * int64(g7_19) | ||||||
|  | 	f5g8_19 := int64(f5) * int64(g8_19) | ||||||
|  | 	f5g9_38 := int64(f5_2) * int64(g9_19) | ||||||
|  | 	f6g0 := int64(f6) * int64(g0) | ||||||
|  | 	f6g1 := int64(f6) * int64(g1) | ||||||
|  | 	f6g2 := int64(f6) * int64(g2) | ||||||
|  | 	f6g3 := int64(f6) * int64(g3) | ||||||
|  | 	f6g4_19 := int64(f6) * int64(g4_19) | ||||||
|  | 	f6g5_19 := int64(f6) * int64(g5_19) | ||||||
|  | 	f6g6_19 := int64(f6) * int64(g6_19) | ||||||
|  | 	f6g7_19 := int64(f6) * int64(g7_19) | ||||||
|  | 	f6g8_19 := int64(f6) * int64(g8_19) | ||||||
|  | 	f6g9_19 := int64(f6) * int64(g9_19) | ||||||
|  | 	f7g0 := int64(f7) * int64(g0) | ||||||
|  | 	f7g1_2 := int64(f7_2) * int64(g1) | ||||||
|  | 	f7g2 := int64(f7) * int64(g2) | ||||||
|  | 	f7g3_38 := int64(f7_2) * int64(g3_19) | ||||||
|  | 	f7g4_19 := int64(f7) * int64(g4_19) | ||||||
|  | 	f7g5_38 := int64(f7_2) * int64(g5_19) | ||||||
|  | 	f7g6_19 := int64(f7) * int64(g6_19) | ||||||
|  | 	f7g7_38 := int64(f7_2) * int64(g7_19) | ||||||
|  | 	f7g8_19 := int64(f7) * int64(g8_19) | ||||||
|  | 	f7g9_38 := int64(f7_2) * int64(g9_19) | ||||||
|  | 	f8g0 := int64(f8) * int64(g0) | ||||||
|  | 	f8g1 := int64(f8) * int64(g1) | ||||||
|  | 	f8g2_19 := int64(f8) * int64(g2_19) | ||||||
|  | 	f8g3_19 := int64(f8) * int64(g3_19) | ||||||
|  | 	f8g4_19 := int64(f8) * int64(g4_19) | ||||||
|  | 	f8g5_19 := int64(f8) * int64(g5_19) | ||||||
|  | 	f8g6_19 := int64(f8) * int64(g6_19) | ||||||
|  | 	f8g7_19 := int64(f8) * int64(g7_19) | ||||||
|  | 	f8g8_19 := int64(f8) * int64(g8_19) | ||||||
|  | 	f8g9_19 := int64(f8) * int64(g9_19) | ||||||
|  | 	f9g0 := int64(f9) * int64(g0) | ||||||
|  | 	f9g1_38 := int64(f9_2) * int64(g1_19) | ||||||
|  | 	f9g2_19 := int64(f9) * int64(g2_19) | ||||||
|  | 	f9g3_38 := int64(f9_2) * int64(g3_19) | ||||||
|  | 	f9g4_19 := int64(f9) * int64(g4_19) | ||||||
|  | 	f9g5_38 := int64(f9_2) * int64(g5_19) | ||||||
|  | 	f9g6_19 := int64(f9) * int64(g6_19) | ||||||
|  | 	f9g7_38 := int64(f9_2) * int64(g7_19) | ||||||
|  | 	f9g8_19 := int64(f9) * int64(g8_19) | ||||||
|  | 	f9g9_38 := int64(f9_2) * int64(g9_19) | ||||||
|  | 	h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38 | ||||||
|  | 	h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19 | ||||||
|  | 	h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38 | ||||||
|  | 	h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19 | ||||||
|  | 	h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38 | ||||||
|  | 	h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19 | ||||||
|  | 	h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38 | ||||||
|  | 	h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19 | ||||||
|  | 	h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38 | ||||||
|  | 	h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0 | ||||||
|  | 	var carry [10]int64 | ||||||
|  |  | ||||||
|  | 	// |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38)) | ||||||
|  | 	//   i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8 | ||||||
|  | 	// |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19)) | ||||||
|  | 	//   i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9 | ||||||
|  |  | ||||||
|  | 	carry[0] = (h0 + (1 << 25)) >> 26 | ||||||
|  | 	h1 += carry[0] | ||||||
|  | 	h0 -= carry[0] << 26 | ||||||
|  | 	carry[4] = (h4 + (1 << 25)) >> 26 | ||||||
|  | 	h5 += carry[4] | ||||||
|  | 	h4 -= carry[4] << 26 | ||||||
|  | 	// |h0| <= 2^25 | ||||||
|  | 	// |h4| <= 2^25 | ||||||
|  | 	// |h1| <= 1.51*2^58 | ||||||
|  | 	// |h5| <= 1.51*2^58 | ||||||
|  |  | ||||||
|  | 	carry[1] = (h1 + (1 << 24)) >> 25 | ||||||
|  | 	h2 += carry[1] | ||||||
|  | 	h1 -= carry[1] << 25 | ||||||
|  | 	carry[5] = (h5 + (1 << 24)) >> 25 | ||||||
|  | 	h6 += carry[5] | ||||||
|  | 	h5 -= carry[5] << 25 | ||||||
|  | 	// |h1| <= 2^24; from now on fits into int32 | ||||||
|  | 	// |h5| <= 2^24; from now on fits into int32 | ||||||
|  | 	// |h2| <= 1.21*2^59 | ||||||
|  | 	// |h6| <= 1.21*2^59 | ||||||
|  |  | ||||||
|  | 	carry[2] = (h2 + (1 << 25)) >> 26 | ||||||
|  | 	h3 += carry[2] | ||||||
|  | 	h2 -= carry[2] << 26 | ||||||
|  | 	carry[6] = (h6 + (1 << 25)) >> 26 | ||||||
|  | 	h7 += carry[6] | ||||||
|  | 	h6 -= carry[6] << 26 | ||||||
|  | 	// |h2| <= 2^25; from now on fits into int32 unchanged | ||||||
|  | 	// |h6| <= 2^25; from now on fits into int32 unchanged | ||||||
|  | 	// |h3| <= 1.51*2^58 | ||||||
|  | 	// |h7| <= 1.51*2^58 | ||||||
|  |  | ||||||
|  | 	carry[3] = (h3 + (1 << 24)) >> 25 | ||||||
|  | 	h4 += carry[3] | ||||||
|  | 	h3 -= carry[3] << 25 | ||||||
|  | 	carry[7] = (h7 + (1 << 24)) >> 25 | ||||||
|  | 	h8 += carry[7] | ||||||
|  | 	h7 -= carry[7] << 25 | ||||||
|  | 	// |h3| <= 2^24; from now on fits into int32 unchanged | ||||||
|  | 	// |h7| <= 2^24; from now on fits into int32 unchanged | ||||||
|  | 	// |h4| <= 1.52*2^33 | ||||||
|  | 	// |h8| <= 1.52*2^33 | ||||||
|  |  | ||||||
|  | 	carry[4] = (h4 + (1 << 25)) >> 26 | ||||||
|  | 	h5 += carry[4] | ||||||
|  | 	h4 -= carry[4] << 26 | ||||||
|  | 	carry[8] = (h8 + (1 << 25)) >> 26 | ||||||
|  | 	h9 += carry[8] | ||||||
|  | 	h8 -= carry[8] << 26 | ||||||
|  | 	// |h4| <= 2^25; from now on fits into int32 unchanged | ||||||
|  | 	// |h8| <= 2^25; from now on fits into int32 unchanged | ||||||
|  | 	// |h5| <= 1.01*2^24 | ||||||
|  | 	// |h9| <= 1.51*2^58 | ||||||
|  |  | ||||||
|  | 	carry[9] = (h9 + (1 << 24)) >> 25 | ||||||
|  | 	h0 += carry[9] * 19 | ||||||
|  | 	h9 -= carry[9] << 25 | ||||||
|  | 	// |h9| <= 2^24; from now on fits into int32 unchanged | ||||||
|  | 	// |h0| <= 1.8*2^37 | ||||||
|  |  | ||||||
|  | 	carry[0] = (h0 + (1 << 25)) >> 26 | ||||||
|  | 	h1 += carry[0] | ||||||
|  | 	h0 -= carry[0] << 26 | ||||||
|  | 	// |h0| <= 2^25; from now on fits into int32 unchanged | ||||||
|  | 	// |h1| <= 1.01*2^24 | ||||||
|  |  | ||||||
|  | 	h[0] = int32(h0) | ||||||
|  | 	h[1] = int32(h1) | ||||||
|  | 	h[2] = int32(h2) | ||||||
|  | 	h[3] = int32(h3) | ||||||
|  | 	h[4] = int32(h4) | ||||||
|  | 	h[5] = int32(h5) | ||||||
|  | 	h[6] = int32(h6) | ||||||
|  | 	h[7] = int32(h7) | ||||||
|  | 	h[8] = int32(h8) | ||||||
|  | 	h[9] = int32(h9) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // feSquare calculates h = f*f. Can overlap h with f. | ||||||
|  | // | ||||||
|  | // Preconditions: | ||||||
|  | //    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | ||||||
|  | // | ||||||
|  | // Postconditions: | ||||||
|  | //    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | ||||||
|  | func feSquare(h, f *fieldElement) { | ||||||
|  | 	f0 := f[0] | ||||||
|  | 	f1 := f[1] | ||||||
|  | 	f2 := f[2] | ||||||
|  | 	f3 := f[3] | ||||||
|  | 	f4 := f[4] | ||||||
|  | 	f5 := f[5] | ||||||
|  | 	f6 := f[6] | ||||||
|  | 	f7 := f[7] | ||||||
|  | 	f8 := f[8] | ||||||
|  | 	f9 := f[9] | ||||||
|  | 	f0_2 := 2 * f0 | ||||||
|  | 	f1_2 := 2 * f1 | ||||||
|  | 	f2_2 := 2 * f2 | ||||||
|  | 	f3_2 := 2 * f3 | ||||||
|  | 	f4_2 := 2 * f4 | ||||||
|  | 	f5_2 := 2 * f5 | ||||||
|  | 	f6_2 := 2 * f6 | ||||||
|  | 	f7_2 := 2 * f7 | ||||||
|  | 	f5_38 := 38 * f5 // 1.31*2^30 | ||||||
|  | 	f6_19 := 19 * f6 // 1.31*2^30 | ||||||
|  | 	f7_38 := 38 * f7 // 1.31*2^30 | ||||||
|  | 	f8_19 := 19 * f8 // 1.31*2^30 | ||||||
|  | 	f9_38 := 38 * f9 // 1.31*2^30 | ||||||
|  | 	f0f0 := int64(f0) * int64(f0) | ||||||
|  | 	f0f1_2 := int64(f0_2) * int64(f1) | ||||||
|  | 	f0f2_2 := int64(f0_2) * int64(f2) | ||||||
|  | 	f0f3_2 := int64(f0_2) * int64(f3) | ||||||
|  | 	f0f4_2 := int64(f0_2) * int64(f4) | ||||||
|  | 	f0f5_2 := int64(f0_2) * int64(f5) | ||||||
|  | 	f0f6_2 := int64(f0_2) * int64(f6) | ||||||
|  | 	f0f7_2 := int64(f0_2) * int64(f7) | ||||||
|  | 	f0f8_2 := int64(f0_2) * int64(f8) | ||||||
|  | 	f0f9_2 := int64(f0_2) * int64(f9) | ||||||
|  | 	f1f1_2 := int64(f1_2) * int64(f1) | ||||||
|  | 	f1f2_2 := int64(f1_2) * int64(f2) | ||||||
|  | 	f1f3_4 := int64(f1_2) * int64(f3_2) | ||||||
|  | 	f1f4_2 := int64(f1_2) * int64(f4) | ||||||
|  | 	f1f5_4 := int64(f1_2) * int64(f5_2) | ||||||
|  | 	f1f6_2 := int64(f1_2) * int64(f6) | ||||||
|  | 	f1f7_4 := int64(f1_2) * int64(f7_2) | ||||||
|  | 	f1f8_2 := int64(f1_2) * int64(f8) | ||||||
|  | 	f1f9_76 := int64(f1_2) * int64(f9_38) | ||||||
|  | 	f2f2 := int64(f2) * int64(f2) | ||||||
|  | 	f2f3_2 := int64(f2_2) * int64(f3) | ||||||
|  | 	f2f4_2 := int64(f2_2) * int64(f4) | ||||||
|  | 	f2f5_2 := int64(f2_2) * int64(f5) | ||||||
|  | 	f2f6_2 := int64(f2_2) * int64(f6) | ||||||
|  | 	f2f7_2 := int64(f2_2) * int64(f7) | ||||||
|  | 	f2f8_38 := int64(f2_2) * int64(f8_19) | ||||||
|  | 	f2f9_38 := int64(f2) * int64(f9_38) | ||||||
|  | 	f3f3_2 := int64(f3_2) * int64(f3) | ||||||
|  | 	f3f4_2 := int64(f3_2) * int64(f4) | ||||||
|  | 	f3f5_4 := int64(f3_2) * int64(f5_2) | ||||||
|  | 	f3f6_2 := int64(f3_2) * int64(f6) | ||||||
|  | 	f3f7_76 := int64(f3_2) * int64(f7_38) | ||||||
|  | 	f3f8_38 := int64(f3_2) * int64(f8_19) | ||||||
|  | 	f3f9_76 := int64(f3_2) * int64(f9_38) | ||||||
|  | 	f4f4 := int64(f4) * int64(f4) | ||||||
|  | 	f4f5_2 := int64(f4_2) * int64(f5) | ||||||
|  | 	f4f6_38 := int64(f4_2) * int64(f6_19) | ||||||
|  | 	f4f7_38 := int64(f4) * int64(f7_38) | ||||||
|  | 	f4f8_38 := int64(f4_2) * int64(f8_19) | ||||||
|  | 	f4f9_38 := int64(f4) * int64(f9_38) | ||||||
|  | 	f5f5_38 := int64(f5) * int64(f5_38) | ||||||
|  | 	f5f6_38 := int64(f5_2) * int64(f6_19) | ||||||
|  | 	f5f7_76 := int64(f5_2) * int64(f7_38) | ||||||
|  | 	f5f8_38 := int64(f5_2) * int64(f8_19) | ||||||
|  | 	f5f9_76 := int64(f5_2) * int64(f9_38) | ||||||
|  | 	f6f6_19 := int64(f6) * int64(f6_19) | ||||||
|  | 	f6f7_38 := int64(f6) * int64(f7_38) | ||||||
|  | 	f6f8_38 := int64(f6_2) * int64(f8_19) | ||||||
|  | 	f6f9_38 := int64(f6) * int64(f9_38) | ||||||
|  | 	f7f7_38 := int64(f7) * int64(f7_38) | ||||||
|  | 	f7f8_38 := int64(f7_2) * int64(f8_19) | ||||||
|  | 	f7f9_76 := int64(f7_2) * int64(f9_38) | ||||||
|  | 	f8f8_19 := int64(f8) * int64(f8_19) | ||||||
|  | 	f8f9_38 := int64(f8) * int64(f9_38) | ||||||
|  | 	f9f9_38 := int64(f9) * int64(f9_38) | ||||||
|  | 	h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38 | ||||||
|  | 	h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38 | ||||||
|  | 	h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19 | ||||||
|  | 	h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38 | ||||||
|  | 	h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38 | ||||||
|  | 	h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38 | ||||||
|  | 	h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19 | ||||||
|  | 	h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38 | ||||||
|  | 	h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38 | ||||||
|  | 	h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2 | ||||||
|  | 	var carry [10]int64 | ||||||
|  |  | ||||||
|  | 	carry[0] = (h0 + (1 << 25)) >> 26 | ||||||
|  | 	h1 += carry[0] | ||||||
|  | 	h0 -= carry[0] << 26 | ||||||
|  | 	carry[4] = (h4 + (1 << 25)) >> 26 | ||||||
|  | 	h5 += carry[4] | ||||||
|  | 	h4 -= carry[4] << 26 | ||||||
|  |  | ||||||
|  | 	carry[1] = (h1 + (1 << 24)) >> 25 | ||||||
|  | 	h2 += carry[1] | ||||||
|  | 	h1 -= carry[1] << 25 | ||||||
|  | 	carry[5] = (h5 + (1 << 24)) >> 25 | ||||||
|  | 	h6 += carry[5] | ||||||
|  | 	h5 -= carry[5] << 25 | ||||||
|  |  | ||||||
|  | 	carry[2] = (h2 + (1 << 25)) >> 26 | ||||||
|  | 	h3 += carry[2] | ||||||
|  | 	h2 -= carry[2] << 26 | ||||||
|  | 	carry[6] = (h6 + (1 << 25)) >> 26 | ||||||
|  | 	h7 += carry[6] | ||||||
|  | 	h6 -= carry[6] << 26 | ||||||
|  |  | ||||||
|  | 	carry[3] = (h3 + (1 << 24)) >> 25 | ||||||
|  | 	h4 += carry[3] | ||||||
|  | 	h3 -= carry[3] << 25 | ||||||
|  | 	carry[7] = (h7 + (1 << 24)) >> 25 | ||||||
|  | 	h8 += carry[7] | ||||||
|  | 	h7 -= carry[7] << 25 | ||||||
|  |  | ||||||
|  | 	carry[4] = (h4 + (1 << 25)) >> 26 | ||||||
|  | 	h5 += carry[4] | ||||||
|  | 	h4 -= carry[4] << 26 | ||||||
|  | 	carry[8] = (h8 + (1 << 25)) >> 26 | ||||||
|  | 	h9 += carry[8] | ||||||
|  | 	h8 -= carry[8] << 26 | ||||||
|  |  | ||||||
|  | 	carry[9] = (h9 + (1 << 24)) >> 25 | ||||||
|  | 	h0 += carry[9] * 19 | ||||||
|  | 	h9 -= carry[9] << 25 | ||||||
|  |  | ||||||
|  | 	carry[0] = (h0 + (1 << 25)) >> 26 | ||||||
|  | 	h1 += carry[0] | ||||||
|  | 	h0 -= carry[0] << 26 | ||||||
|  |  | ||||||
|  | 	h[0] = int32(h0) | ||||||
|  | 	h[1] = int32(h1) | ||||||
|  | 	h[2] = int32(h2) | ||||||
|  | 	h[3] = int32(h3) | ||||||
|  | 	h[4] = int32(h4) | ||||||
|  | 	h[5] = int32(h5) | ||||||
|  | 	h[6] = int32(h6) | ||||||
|  | 	h[7] = int32(h7) | ||||||
|  | 	h[8] = int32(h8) | ||||||
|  | 	h[9] = int32(h9) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // feMul121666 calculates h = f * 121666. Can overlap h with f. | ||||||
|  | // | ||||||
|  | // Preconditions: | ||||||
|  | //    |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. | ||||||
|  | // | ||||||
|  | // Postconditions: | ||||||
|  | //    |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. | ||||||
|  | func feMul121666(h, f *fieldElement) { | ||||||
|  | 	h0 := int64(f[0]) * 121666 | ||||||
|  | 	h1 := int64(f[1]) * 121666 | ||||||
|  | 	h2 := int64(f[2]) * 121666 | ||||||
|  | 	h3 := int64(f[3]) * 121666 | ||||||
|  | 	h4 := int64(f[4]) * 121666 | ||||||
|  | 	h5 := int64(f[5]) * 121666 | ||||||
|  | 	h6 := int64(f[6]) * 121666 | ||||||
|  | 	h7 := int64(f[7]) * 121666 | ||||||
|  | 	h8 := int64(f[8]) * 121666 | ||||||
|  | 	h9 := int64(f[9]) * 121666 | ||||||
|  | 	var carry [10]int64 | ||||||
|  |  | ||||||
|  | 	carry[9] = (h9 + (1 << 24)) >> 25 | ||||||
|  | 	h0 += carry[9] * 19 | ||||||
|  | 	h9 -= carry[9] << 25 | ||||||
|  | 	carry[1] = (h1 + (1 << 24)) >> 25 | ||||||
|  | 	h2 += carry[1] | ||||||
|  | 	h1 -= carry[1] << 25 | ||||||
|  | 	carry[3] = (h3 + (1 << 24)) >> 25 | ||||||
|  | 	h4 += carry[3] | ||||||
|  | 	h3 -= carry[3] << 25 | ||||||
|  | 	carry[5] = (h5 + (1 << 24)) >> 25 | ||||||
|  | 	h6 += carry[5] | ||||||
|  | 	h5 -= carry[5] << 25 | ||||||
|  | 	carry[7] = (h7 + (1 << 24)) >> 25 | ||||||
|  | 	h8 += carry[7] | ||||||
|  | 	h7 -= carry[7] << 25 | ||||||
|  |  | ||||||
|  | 	carry[0] = (h0 + (1 << 25)) >> 26 | ||||||
|  | 	h1 += carry[0] | ||||||
|  | 	h0 -= carry[0] << 26 | ||||||
|  | 	carry[2] = (h2 + (1 << 25)) >> 26 | ||||||
|  | 	h3 += carry[2] | ||||||
|  | 	h2 -= carry[2] << 26 | ||||||
|  | 	carry[4] = (h4 + (1 << 25)) >> 26 | ||||||
|  | 	h5 += carry[4] | ||||||
|  | 	h4 -= carry[4] << 26 | ||||||
|  | 	carry[6] = (h6 + (1 << 25)) >> 26 | ||||||
|  | 	h7 += carry[6] | ||||||
|  | 	h6 -= carry[6] << 26 | ||||||
|  | 	carry[8] = (h8 + (1 << 25)) >> 26 | ||||||
|  | 	h9 += carry[8] | ||||||
|  | 	h8 -= carry[8] << 26 | ||||||
|  |  | ||||||
|  | 	h[0] = int32(h0) | ||||||
|  | 	h[1] = int32(h1) | ||||||
|  | 	h[2] = int32(h2) | ||||||
|  | 	h[3] = int32(h3) | ||||||
|  | 	h[4] = int32(h4) | ||||||
|  | 	h[5] = int32(h5) | ||||||
|  | 	h[6] = int32(h6) | ||||||
|  | 	h[7] = int32(h7) | ||||||
|  | 	h[8] = int32(h8) | ||||||
|  | 	h[9] = int32(h9) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // feInvert sets out = z^-1. | ||||||
|  | func feInvert(out, z *fieldElement) { | ||||||
|  | 	var t0, t1, t2, t3 fieldElement | ||||||
|  | 	var i int | ||||||
|  |  | ||||||
|  | 	feSquare(&t0, z) | ||||||
|  | 	for i = 1; i < 1; i++ { | ||||||
|  | 		feSquare(&t0, &t0) | ||||||
|  | 	} | ||||||
|  | 	feSquare(&t1, &t0) | ||||||
|  | 	for i = 1; i < 2; i++ { | ||||||
|  | 		feSquare(&t1, &t1) | ||||||
|  | 	} | ||||||
|  | 	feMul(&t1, z, &t1) | ||||||
|  | 	feMul(&t0, &t0, &t1) | ||||||
|  | 	feSquare(&t2, &t0) | ||||||
|  | 	for i = 1; i < 1; i++ { | ||||||
|  | 		feSquare(&t2, &t2) | ||||||
|  | 	} | ||||||
|  | 	feMul(&t1, &t1, &t2) | ||||||
|  | 	feSquare(&t2, &t1) | ||||||
|  | 	for i = 1; i < 5; i++ { | ||||||
|  | 		feSquare(&t2, &t2) | ||||||
|  | 	} | ||||||
|  | 	feMul(&t1, &t2, &t1) | ||||||
|  | 	feSquare(&t2, &t1) | ||||||
|  | 	for i = 1; i < 10; i++ { | ||||||
|  | 		feSquare(&t2, &t2) | ||||||
|  | 	} | ||||||
|  | 	feMul(&t2, &t2, &t1) | ||||||
|  | 	feSquare(&t3, &t2) | ||||||
|  | 	for i = 1; i < 20; i++ { | ||||||
|  | 		feSquare(&t3, &t3) | ||||||
|  | 	} | ||||||
|  | 	feMul(&t2, &t3, &t2) | ||||||
|  | 	feSquare(&t2, &t2) | ||||||
|  | 	for i = 1; i < 10; i++ { | ||||||
|  | 		feSquare(&t2, &t2) | ||||||
|  | 	} | ||||||
|  | 	feMul(&t1, &t2, &t1) | ||||||
|  | 	feSquare(&t2, &t1) | ||||||
|  | 	for i = 1; i < 50; i++ { | ||||||
|  | 		feSquare(&t2, &t2) | ||||||
|  | 	} | ||||||
|  | 	feMul(&t2, &t2, &t1) | ||||||
|  | 	feSquare(&t3, &t2) | ||||||
|  | 	for i = 1; i < 100; i++ { | ||||||
|  | 		feSquare(&t3, &t3) | ||||||
|  | 	} | ||||||
|  | 	feMul(&t2, &t3, &t2) | ||||||
|  | 	feSquare(&t2, &t2) | ||||||
|  | 	for i = 1; i < 50; i++ { | ||||||
|  | 		feSquare(&t2, &t2) | ||||||
|  | 	} | ||||||
|  | 	feMul(&t1, &t2, &t1) | ||||||
|  | 	feSquare(&t1, &t1) | ||||||
|  | 	for i = 1; i < 5; i++ { | ||||||
|  | 		feSquare(&t1, &t1) | ||||||
|  | 	} | ||||||
|  | 	feMul(out, &t1, &t0) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func scalarMult(out, in, base *[32]byte) { | ||||||
|  | 	var e [32]byte | ||||||
|  |  | ||||||
|  | 	copy(e[:], in[:]) | ||||||
|  | 	e[0] &= 248 | ||||||
|  | 	e[31] &= 127 | ||||||
|  | 	e[31] |= 64 | ||||||
|  |  | ||||||
|  | 	var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement | ||||||
|  | 	feFromBytes(&x1, base) | ||||||
|  | 	feOne(&x2) | ||||||
|  | 	feCopy(&x3, &x1) | ||||||
|  | 	feOne(&z3) | ||||||
|  |  | ||||||
|  | 	swap := int32(0) | ||||||
|  | 	for pos := 254; pos >= 0; pos-- { | ||||||
|  | 		b := e[pos/8] >> uint(pos&7) | ||||||
|  | 		b &= 1 | ||||||
|  | 		swap ^= int32(b) | ||||||
|  | 		feCSwap(&x2, &x3, swap) | ||||||
|  | 		feCSwap(&z2, &z3, swap) | ||||||
|  | 		swap = int32(b) | ||||||
|  |  | ||||||
|  | 		feSub(&tmp0, &x3, &z3) | ||||||
|  | 		feSub(&tmp1, &x2, &z2) | ||||||
|  | 		feAdd(&x2, &x2, &z2) | ||||||
|  | 		feAdd(&z2, &x3, &z3) | ||||||
|  | 		feMul(&z3, &tmp0, &x2) | ||||||
|  | 		feMul(&z2, &z2, &tmp1) | ||||||
|  | 		feSquare(&tmp0, &tmp1) | ||||||
|  | 		feSquare(&tmp1, &x2) | ||||||
|  | 		feAdd(&x3, &z3, &z2) | ||||||
|  | 		feSub(&z2, &z3, &z2) | ||||||
|  | 		feMul(&x2, &tmp1, &tmp0) | ||||||
|  | 		feSub(&tmp1, &tmp1, &tmp0) | ||||||
|  | 		feSquare(&z2, &z2) | ||||||
|  | 		feMul121666(&z3, &tmp1) | ||||||
|  | 		feSquare(&x3, &x3) | ||||||
|  | 		feAdd(&tmp0, &tmp0, &z3) | ||||||
|  | 		feMul(&z3, &x1, &z2) | ||||||
|  | 		feMul(&z2, &tmp1, &tmp0) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	feCSwap(&x2, &x3, swap) | ||||||
|  | 	feCSwap(&z2, &z3, swap) | ||||||
|  |  | ||||||
|  | 	feInvert(&z2, &z2) | ||||||
|  | 	feMul(&x2, &x2, &z2) | ||||||
|  | 	feToBytes(out, &x2) | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								vendor/golang.org/x/crypto/curve25519/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/golang.org/x/crypto/curve25519/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | // Copyright 2012 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 curve25519 provides an implementation of scalar multiplication on | ||||||
|  | // the elliptic curve known as curve25519. See https://cr.yp.to/ecdh.html | ||||||
|  | package curve25519 // import "golang.org/x/crypto/curve25519" | ||||||
|  |  | ||||||
|  | // basePoint is the x coordinate of the generator of the curve. | ||||||
|  | var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} | ||||||
|  |  | ||||||
|  | // ScalarMult sets dst to the product in*base where dst and base are the x | ||||||
|  | // coordinates of group points and all values are in little-endian form. | ||||||
|  | func ScalarMult(dst, in, base *[32]byte) { | ||||||
|  | 	scalarMult(dst, in, base) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ScalarBaseMult sets dst to the product in*base where dst and base are the x | ||||||
|  | // coordinates of group points, base is the standard generator and all values | ||||||
|  | // are in little-endian form. | ||||||
|  | func ScalarBaseMult(dst, in *[32]byte) { | ||||||
|  | 	ScalarMult(dst, in, &basePoint) | ||||||
|  | } | ||||||
							
								
								
									
										73
									
								
								vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | |||||||
|  | // Copyright 2012 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. | ||||||
|  |  | ||||||
|  | // This code was translated into a form compatible with 6a from the public | ||||||
|  | // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | ||||||
|  |  | ||||||
|  | // +build amd64,!gccgo,!appengine | ||||||
|  |  | ||||||
|  | #include "const_amd64.h" | ||||||
|  |  | ||||||
|  | // func freeze(inout *[5]uint64) | ||||||
|  | TEXT ·freeze(SB),7,$0-8 | ||||||
|  | 	MOVQ inout+0(FP), DI | ||||||
|  |  | ||||||
|  | 	MOVQ 0(DI),SI | ||||||
|  | 	MOVQ 8(DI),DX | ||||||
|  | 	MOVQ 16(DI),CX | ||||||
|  | 	MOVQ 24(DI),R8 | ||||||
|  | 	MOVQ 32(DI),R9 | ||||||
|  | 	MOVQ $REDMASK51,AX | ||||||
|  | 	MOVQ AX,R10 | ||||||
|  | 	SUBQ $18,R10 | ||||||
|  | 	MOVQ $3,R11 | ||||||
|  | REDUCELOOP: | ||||||
|  | 	MOVQ SI,R12 | ||||||
|  | 	SHRQ $51,R12 | ||||||
|  | 	ANDQ AX,SI | ||||||
|  | 	ADDQ R12,DX | ||||||
|  | 	MOVQ DX,R12 | ||||||
|  | 	SHRQ $51,R12 | ||||||
|  | 	ANDQ AX,DX | ||||||
|  | 	ADDQ R12,CX | ||||||
|  | 	MOVQ CX,R12 | ||||||
|  | 	SHRQ $51,R12 | ||||||
|  | 	ANDQ AX,CX | ||||||
|  | 	ADDQ R12,R8 | ||||||
|  | 	MOVQ R8,R12 | ||||||
|  | 	SHRQ $51,R12 | ||||||
|  | 	ANDQ AX,R8 | ||||||
|  | 	ADDQ R12,R9 | ||||||
|  | 	MOVQ R9,R12 | ||||||
|  | 	SHRQ $51,R12 | ||||||
|  | 	ANDQ AX,R9 | ||||||
|  | 	IMUL3Q $19,R12,R12 | ||||||
|  | 	ADDQ R12,SI | ||||||
|  | 	SUBQ $1,R11 | ||||||
|  | 	JA REDUCELOOP | ||||||
|  | 	MOVQ $1,R12 | ||||||
|  | 	CMPQ R10,SI | ||||||
|  | 	CMOVQLT R11,R12 | ||||||
|  | 	CMPQ AX,DX | ||||||
|  | 	CMOVQNE R11,R12 | ||||||
|  | 	CMPQ AX,CX | ||||||
|  | 	CMOVQNE R11,R12 | ||||||
|  | 	CMPQ AX,R8 | ||||||
|  | 	CMOVQNE R11,R12 | ||||||
|  | 	CMPQ AX,R9 | ||||||
|  | 	CMOVQNE R11,R12 | ||||||
|  | 	NEGQ R12 | ||||||
|  | 	ANDQ R12,AX | ||||||
|  | 	ANDQ R12,R10 | ||||||
|  | 	SUBQ R10,SI | ||||||
|  | 	SUBQ AX,DX | ||||||
|  | 	SUBQ AX,CX | ||||||
|  | 	SUBQ AX,R8 | ||||||
|  | 	SUBQ AX,R9 | ||||||
|  | 	MOVQ SI,0(DI) | ||||||
|  | 	MOVQ DX,8(DI) | ||||||
|  | 	MOVQ CX,16(DI) | ||||||
|  | 	MOVQ R8,24(DI) | ||||||
|  | 	MOVQ R9,32(DI) | ||||||
|  | 	RET | ||||||
							
								
								
									
										1377
									
								
								vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1377
									
								
								vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										240
									
								
								vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,240 @@ | |||||||
|  | // Copyright 2012 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. | ||||||
|  |  | ||||||
|  | // +build amd64,!gccgo,!appengine | ||||||
|  |  | ||||||
|  | package curve25519 | ||||||
|  |  | ||||||
|  | // These functions are implemented in the .s files. The names of the functions | ||||||
|  | // in the rest of the file are also taken from the SUPERCOP sources to help | ||||||
|  | // people following along. | ||||||
|  |  | ||||||
|  | //go:noescape | ||||||
|  |  | ||||||
|  | func cswap(inout *[5]uint64, v uint64) | ||||||
|  |  | ||||||
|  | //go:noescape | ||||||
|  |  | ||||||
|  | func ladderstep(inout *[5][5]uint64) | ||||||
|  |  | ||||||
|  | //go:noescape | ||||||
|  |  | ||||||
|  | func freeze(inout *[5]uint64) | ||||||
|  |  | ||||||
|  | //go:noescape | ||||||
|  |  | ||||||
|  | func mul(dest, a, b *[5]uint64) | ||||||
|  |  | ||||||
|  | //go:noescape | ||||||
|  |  | ||||||
|  | func square(out, in *[5]uint64) | ||||||
|  |  | ||||||
|  | // mladder uses a Montgomery ladder to calculate (xr/zr) *= s. | ||||||
|  | func mladder(xr, zr *[5]uint64, s *[32]byte) { | ||||||
|  | 	var work [5][5]uint64 | ||||||
|  |  | ||||||
|  | 	work[0] = *xr | ||||||
|  | 	setint(&work[1], 1) | ||||||
|  | 	setint(&work[2], 0) | ||||||
|  | 	work[3] = *xr | ||||||
|  | 	setint(&work[4], 1) | ||||||
|  |  | ||||||
|  | 	j := uint(6) | ||||||
|  | 	var prevbit byte | ||||||
|  |  | ||||||
|  | 	for i := 31; i >= 0; i-- { | ||||||
|  | 		for j < 8 { | ||||||
|  | 			bit := ((*s)[i] >> j) & 1 | ||||||
|  | 			swap := bit ^ prevbit | ||||||
|  | 			prevbit = bit | ||||||
|  | 			cswap(&work[1], uint64(swap)) | ||||||
|  | 			ladderstep(&work) | ||||||
|  | 			j-- | ||||||
|  | 		} | ||||||
|  | 		j = 7 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	*xr = work[1] | ||||||
|  | 	*zr = work[2] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func scalarMult(out, in, base *[32]byte) { | ||||||
|  | 	var e [32]byte | ||||||
|  | 	copy(e[:], (*in)[:]) | ||||||
|  | 	e[0] &= 248 | ||||||
|  | 	e[31] &= 127 | ||||||
|  | 	e[31] |= 64 | ||||||
|  |  | ||||||
|  | 	var t, z [5]uint64 | ||||||
|  | 	unpack(&t, base) | ||||||
|  | 	mladder(&t, &z, &e) | ||||||
|  | 	invert(&z, &z) | ||||||
|  | 	mul(&t, &t, &z) | ||||||
|  | 	pack(out, &t) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func setint(r *[5]uint64, v uint64) { | ||||||
|  | 	r[0] = v | ||||||
|  | 	r[1] = 0 | ||||||
|  | 	r[2] = 0 | ||||||
|  | 	r[3] = 0 | ||||||
|  | 	r[4] = 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // unpack sets r = x where r consists of 5, 51-bit limbs in little-endian | ||||||
|  | // order. | ||||||
|  | func unpack(r *[5]uint64, x *[32]byte) { | ||||||
|  | 	r[0] = uint64(x[0]) | | ||||||
|  | 		uint64(x[1])<<8 | | ||||||
|  | 		uint64(x[2])<<16 | | ||||||
|  | 		uint64(x[3])<<24 | | ||||||
|  | 		uint64(x[4])<<32 | | ||||||
|  | 		uint64(x[5])<<40 | | ||||||
|  | 		uint64(x[6]&7)<<48 | ||||||
|  |  | ||||||
|  | 	r[1] = uint64(x[6])>>3 | | ||||||
|  | 		uint64(x[7])<<5 | | ||||||
|  | 		uint64(x[8])<<13 | | ||||||
|  | 		uint64(x[9])<<21 | | ||||||
|  | 		uint64(x[10])<<29 | | ||||||
|  | 		uint64(x[11])<<37 | | ||||||
|  | 		uint64(x[12]&63)<<45 | ||||||
|  |  | ||||||
|  | 	r[2] = uint64(x[12])>>6 | | ||||||
|  | 		uint64(x[13])<<2 | | ||||||
|  | 		uint64(x[14])<<10 | | ||||||
|  | 		uint64(x[15])<<18 | | ||||||
|  | 		uint64(x[16])<<26 | | ||||||
|  | 		uint64(x[17])<<34 | | ||||||
|  | 		uint64(x[18])<<42 | | ||||||
|  | 		uint64(x[19]&1)<<50 | ||||||
|  |  | ||||||
|  | 	r[3] = uint64(x[19])>>1 | | ||||||
|  | 		uint64(x[20])<<7 | | ||||||
|  | 		uint64(x[21])<<15 | | ||||||
|  | 		uint64(x[22])<<23 | | ||||||
|  | 		uint64(x[23])<<31 | | ||||||
|  | 		uint64(x[24])<<39 | | ||||||
|  | 		uint64(x[25]&15)<<47 | ||||||
|  |  | ||||||
|  | 	r[4] = uint64(x[25])>>4 | | ||||||
|  | 		uint64(x[26])<<4 | | ||||||
|  | 		uint64(x[27])<<12 | | ||||||
|  | 		uint64(x[28])<<20 | | ||||||
|  | 		uint64(x[29])<<28 | | ||||||
|  | 		uint64(x[30])<<36 | | ||||||
|  | 		uint64(x[31]&127)<<44 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // pack sets out = x where out is the usual, little-endian form of the 5, | ||||||
|  | // 51-bit limbs in x. | ||||||
|  | func pack(out *[32]byte, x *[5]uint64) { | ||||||
|  | 	t := *x | ||||||
|  | 	freeze(&t) | ||||||
|  |  | ||||||
|  | 	out[0] = byte(t[0]) | ||||||
|  | 	out[1] = byte(t[0] >> 8) | ||||||
|  | 	out[2] = byte(t[0] >> 16) | ||||||
|  | 	out[3] = byte(t[0] >> 24) | ||||||
|  | 	out[4] = byte(t[0] >> 32) | ||||||
|  | 	out[5] = byte(t[0] >> 40) | ||||||
|  | 	out[6] = byte(t[0] >> 48) | ||||||
|  |  | ||||||
|  | 	out[6] ^= byte(t[1]<<3) & 0xf8 | ||||||
|  | 	out[7] = byte(t[1] >> 5) | ||||||
|  | 	out[8] = byte(t[1] >> 13) | ||||||
|  | 	out[9] = byte(t[1] >> 21) | ||||||
|  | 	out[10] = byte(t[1] >> 29) | ||||||
|  | 	out[11] = byte(t[1] >> 37) | ||||||
|  | 	out[12] = byte(t[1] >> 45) | ||||||
|  |  | ||||||
|  | 	out[12] ^= byte(t[2]<<6) & 0xc0 | ||||||
|  | 	out[13] = byte(t[2] >> 2) | ||||||
|  | 	out[14] = byte(t[2] >> 10) | ||||||
|  | 	out[15] = byte(t[2] >> 18) | ||||||
|  | 	out[16] = byte(t[2] >> 26) | ||||||
|  | 	out[17] = byte(t[2] >> 34) | ||||||
|  | 	out[18] = byte(t[2] >> 42) | ||||||
|  | 	out[19] = byte(t[2] >> 50) | ||||||
|  |  | ||||||
|  | 	out[19] ^= byte(t[3]<<1) & 0xfe | ||||||
|  | 	out[20] = byte(t[3] >> 7) | ||||||
|  | 	out[21] = byte(t[3] >> 15) | ||||||
|  | 	out[22] = byte(t[3] >> 23) | ||||||
|  | 	out[23] = byte(t[3] >> 31) | ||||||
|  | 	out[24] = byte(t[3] >> 39) | ||||||
|  | 	out[25] = byte(t[3] >> 47) | ||||||
|  |  | ||||||
|  | 	out[25] ^= byte(t[4]<<4) & 0xf0 | ||||||
|  | 	out[26] = byte(t[4] >> 4) | ||||||
|  | 	out[27] = byte(t[4] >> 12) | ||||||
|  | 	out[28] = byte(t[4] >> 20) | ||||||
|  | 	out[29] = byte(t[4] >> 28) | ||||||
|  | 	out[30] = byte(t[4] >> 36) | ||||||
|  | 	out[31] = byte(t[4] >> 44) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // invert calculates r = x^-1 mod p using Fermat's little theorem. | ||||||
|  | func invert(r *[5]uint64, x *[5]uint64) { | ||||||
|  | 	var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64 | ||||||
|  |  | ||||||
|  | 	square(&z2, x)        /* 2 */ | ||||||
|  | 	square(&t, &z2)       /* 4 */ | ||||||
|  | 	square(&t, &t)        /* 8 */ | ||||||
|  | 	mul(&z9, &t, x)       /* 9 */ | ||||||
|  | 	mul(&z11, &z9, &z2)   /* 11 */ | ||||||
|  | 	square(&t, &z11)      /* 22 */ | ||||||
|  | 	mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */ | ||||||
|  |  | ||||||
|  | 	square(&t, &z2_5_0)      /* 2^6 - 2^1 */ | ||||||
|  | 	for i := 1; i < 5; i++ { /* 2^20 - 2^10 */ | ||||||
|  | 		square(&t, &t) | ||||||
|  | 	} | ||||||
|  | 	mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */ | ||||||
|  |  | ||||||
|  | 	square(&t, &z2_10_0)      /* 2^11 - 2^1 */ | ||||||
|  | 	for i := 1; i < 10; i++ { /* 2^20 - 2^10 */ | ||||||
|  | 		square(&t, &t) | ||||||
|  | 	} | ||||||
|  | 	mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */ | ||||||
|  |  | ||||||
|  | 	square(&t, &z2_20_0)      /* 2^21 - 2^1 */ | ||||||
|  | 	for i := 1; i < 20; i++ { /* 2^40 - 2^20 */ | ||||||
|  | 		square(&t, &t) | ||||||
|  | 	} | ||||||
|  | 	mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */ | ||||||
|  |  | ||||||
|  | 	square(&t, &t)            /* 2^41 - 2^1 */ | ||||||
|  | 	for i := 1; i < 10; i++ { /* 2^50 - 2^10 */ | ||||||
|  | 		square(&t, &t) | ||||||
|  | 	} | ||||||
|  | 	mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */ | ||||||
|  |  | ||||||
|  | 	square(&t, &z2_50_0)      /* 2^51 - 2^1 */ | ||||||
|  | 	for i := 1; i < 50; i++ { /* 2^100 - 2^50 */ | ||||||
|  | 		square(&t, &t) | ||||||
|  | 	} | ||||||
|  | 	mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */ | ||||||
|  |  | ||||||
|  | 	square(&t, &z2_100_0)      /* 2^101 - 2^1 */ | ||||||
|  | 	for i := 1; i < 100; i++ { /* 2^200 - 2^100 */ | ||||||
|  | 		square(&t, &t) | ||||||
|  | 	} | ||||||
|  | 	mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */ | ||||||
|  |  | ||||||
|  | 	square(&t, &t)            /* 2^201 - 2^1 */ | ||||||
|  | 	for i := 1; i < 50; i++ { /* 2^250 - 2^50 */ | ||||||
|  | 		square(&t, &t) | ||||||
|  | 	} | ||||||
|  | 	mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */ | ||||||
|  |  | ||||||
|  | 	square(&t, &t) /* 2^251 - 2^1 */ | ||||||
|  | 	square(&t, &t) /* 2^252 - 2^2 */ | ||||||
|  | 	square(&t, &t) /* 2^253 - 2^3 */ | ||||||
|  |  | ||||||
|  | 	square(&t, &t) /* 2^254 - 2^4 */ | ||||||
|  |  | ||||||
|  | 	square(&t, &t)   /* 2^255 - 2^5 */ | ||||||
|  | 	mul(r, &t, &z11) /* 2^255 - 21 */ | ||||||
|  | } | ||||||
							
								
								
									
										169
									
								
								vendor/golang.org/x/crypto/curve25519/mul_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								vendor/golang.org/x/crypto/curve25519/mul_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | |||||||
|  | // Copyright 2012 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. | ||||||
|  |  | ||||||
|  | // This code was translated into a form compatible with 6a from the public | ||||||
|  | // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | ||||||
|  |  | ||||||
|  | // +build amd64,!gccgo,!appengine | ||||||
|  |  | ||||||
|  | #include "const_amd64.h" | ||||||
|  |  | ||||||
|  | // func mul(dest, a, b *[5]uint64) | ||||||
|  | TEXT ·mul(SB),0,$16-24 | ||||||
|  | 	MOVQ dest+0(FP), DI | ||||||
|  | 	MOVQ a+8(FP), SI | ||||||
|  | 	MOVQ b+16(FP), DX | ||||||
|  |  | ||||||
|  | 	MOVQ DX,CX | ||||||
|  | 	MOVQ 24(SI),DX | ||||||
|  | 	IMUL3Q $19,DX,AX | ||||||
|  | 	MOVQ AX,0(SP) | ||||||
|  | 	MULQ 16(CX) | ||||||
|  | 	MOVQ AX,R8 | ||||||
|  | 	MOVQ DX,R9 | ||||||
|  | 	MOVQ 32(SI),DX | ||||||
|  | 	IMUL3Q $19,DX,AX | ||||||
|  | 	MOVQ AX,8(SP) | ||||||
|  | 	MULQ 8(CX) | ||||||
|  | 	ADDQ AX,R8 | ||||||
|  | 	ADCQ DX,R9 | ||||||
|  | 	MOVQ 0(SI),AX | ||||||
|  | 	MULQ 0(CX) | ||||||
|  | 	ADDQ AX,R8 | ||||||
|  | 	ADCQ DX,R9 | ||||||
|  | 	MOVQ 0(SI),AX | ||||||
|  | 	MULQ 8(CX) | ||||||
|  | 	MOVQ AX,R10 | ||||||
|  | 	MOVQ DX,R11 | ||||||
|  | 	MOVQ 0(SI),AX | ||||||
|  | 	MULQ 16(CX) | ||||||
|  | 	MOVQ AX,R12 | ||||||
|  | 	MOVQ DX,R13 | ||||||
|  | 	MOVQ 0(SI),AX | ||||||
|  | 	MULQ 24(CX) | ||||||
|  | 	MOVQ AX,R14 | ||||||
|  | 	MOVQ DX,R15 | ||||||
|  | 	MOVQ 0(SI),AX | ||||||
|  | 	MULQ 32(CX) | ||||||
|  | 	MOVQ AX,BX | ||||||
|  | 	MOVQ DX,BP | ||||||
|  | 	MOVQ 8(SI),AX | ||||||
|  | 	MULQ 0(CX) | ||||||
|  | 	ADDQ AX,R10 | ||||||
|  | 	ADCQ DX,R11 | ||||||
|  | 	MOVQ 8(SI),AX | ||||||
|  | 	MULQ 8(CX) | ||||||
|  | 	ADDQ AX,R12 | ||||||
|  | 	ADCQ DX,R13 | ||||||
|  | 	MOVQ 8(SI),AX | ||||||
|  | 	MULQ 16(CX) | ||||||
|  | 	ADDQ AX,R14 | ||||||
|  | 	ADCQ DX,R15 | ||||||
|  | 	MOVQ 8(SI),AX | ||||||
|  | 	MULQ 24(CX) | ||||||
|  | 	ADDQ AX,BX | ||||||
|  | 	ADCQ DX,BP | ||||||
|  | 	MOVQ 8(SI),DX | ||||||
|  | 	IMUL3Q $19,DX,AX | ||||||
|  | 	MULQ 32(CX) | ||||||
|  | 	ADDQ AX,R8 | ||||||
|  | 	ADCQ DX,R9 | ||||||
|  | 	MOVQ 16(SI),AX | ||||||
|  | 	MULQ 0(CX) | ||||||
|  | 	ADDQ AX,R12 | ||||||
|  | 	ADCQ DX,R13 | ||||||
|  | 	MOVQ 16(SI),AX | ||||||
|  | 	MULQ 8(CX) | ||||||
|  | 	ADDQ AX,R14 | ||||||
|  | 	ADCQ DX,R15 | ||||||
|  | 	MOVQ 16(SI),AX | ||||||
|  | 	MULQ 16(CX) | ||||||
|  | 	ADDQ AX,BX | ||||||
|  | 	ADCQ DX,BP | ||||||
|  | 	MOVQ 16(SI),DX | ||||||
|  | 	IMUL3Q $19,DX,AX | ||||||
|  | 	MULQ 24(CX) | ||||||
|  | 	ADDQ AX,R8 | ||||||
|  | 	ADCQ DX,R9 | ||||||
|  | 	MOVQ 16(SI),DX | ||||||
|  | 	IMUL3Q $19,DX,AX | ||||||
|  | 	MULQ 32(CX) | ||||||
|  | 	ADDQ AX,R10 | ||||||
|  | 	ADCQ DX,R11 | ||||||
|  | 	MOVQ 24(SI),AX | ||||||
|  | 	MULQ 0(CX) | ||||||
|  | 	ADDQ AX,R14 | ||||||
|  | 	ADCQ DX,R15 | ||||||
|  | 	MOVQ 24(SI),AX | ||||||
|  | 	MULQ 8(CX) | ||||||
|  | 	ADDQ AX,BX | ||||||
|  | 	ADCQ DX,BP | ||||||
|  | 	MOVQ 0(SP),AX | ||||||
|  | 	MULQ 24(CX) | ||||||
|  | 	ADDQ AX,R10 | ||||||
|  | 	ADCQ DX,R11 | ||||||
|  | 	MOVQ 0(SP),AX | ||||||
|  | 	MULQ 32(CX) | ||||||
|  | 	ADDQ AX,R12 | ||||||
|  | 	ADCQ DX,R13 | ||||||
|  | 	MOVQ 32(SI),AX | ||||||
|  | 	MULQ 0(CX) | ||||||
|  | 	ADDQ AX,BX | ||||||
|  | 	ADCQ DX,BP | ||||||
|  | 	MOVQ 8(SP),AX | ||||||
|  | 	MULQ 16(CX) | ||||||
|  | 	ADDQ AX,R10 | ||||||
|  | 	ADCQ DX,R11 | ||||||
|  | 	MOVQ 8(SP),AX | ||||||
|  | 	MULQ 24(CX) | ||||||
|  | 	ADDQ AX,R12 | ||||||
|  | 	ADCQ DX,R13 | ||||||
|  | 	MOVQ 8(SP),AX | ||||||
|  | 	MULQ 32(CX) | ||||||
|  | 	ADDQ AX,R14 | ||||||
|  | 	ADCQ DX,R15 | ||||||
|  | 	MOVQ $REDMASK51,SI | ||||||
|  | 	SHLQ $13,R9:R8 | ||||||
|  | 	ANDQ SI,R8 | ||||||
|  | 	SHLQ $13,R11:R10 | ||||||
|  | 	ANDQ SI,R10 | ||||||
|  | 	ADDQ R9,R10 | ||||||
|  | 	SHLQ $13,R13:R12 | ||||||
|  | 	ANDQ SI,R12 | ||||||
|  | 	ADDQ R11,R12 | ||||||
|  | 	SHLQ $13,R15:R14 | ||||||
|  | 	ANDQ SI,R14 | ||||||
|  | 	ADDQ R13,R14 | ||||||
|  | 	SHLQ $13,BP:BX | ||||||
|  | 	ANDQ SI,BX | ||||||
|  | 	ADDQ R15,BX | ||||||
|  | 	IMUL3Q $19,BP,DX | ||||||
|  | 	ADDQ DX,R8 | ||||||
|  | 	MOVQ R8,DX | ||||||
|  | 	SHRQ $51,DX | ||||||
|  | 	ADDQ R10,DX | ||||||
|  | 	MOVQ DX,CX | ||||||
|  | 	SHRQ $51,DX | ||||||
|  | 	ANDQ SI,R8 | ||||||
|  | 	ADDQ R12,DX | ||||||
|  | 	MOVQ DX,R9 | ||||||
|  | 	SHRQ $51,DX | ||||||
|  | 	ANDQ SI,CX | ||||||
|  | 	ADDQ R14,DX | ||||||
|  | 	MOVQ DX,AX | ||||||
|  | 	SHRQ $51,DX | ||||||
|  | 	ANDQ SI,R9 | ||||||
|  | 	ADDQ BX,DX | ||||||
|  | 	MOVQ DX,R10 | ||||||
|  | 	SHRQ $51,DX | ||||||
|  | 	ANDQ SI,AX | ||||||
|  | 	IMUL3Q $19,DX,DX | ||||||
|  | 	ADDQ DX,R8 | ||||||
|  | 	ANDQ SI,R10 | ||||||
|  | 	MOVQ R8,0(DI) | ||||||
|  | 	MOVQ CX,8(DI) | ||||||
|  | 	MOVQ R9,16(DI) | ||||||
|  | 	MOVQ AX,24(DI) | ||||||
|  | 	MOVQ R10,32(DI) | ||||||
|  | 	RET | ||||||
							
								
								
									
										132
									
								
								vendor/golang.org/x/crypto/curve25519/square_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								vendor/golang.org/x/crypto/curve25519/square_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,132 @@ | |||||||
|  | // Copyright 2012 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. | ||||||
|  |  | ||||||
|  | // This code was translated into a form compatible with 6a from the public | ||||||
|  | // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html | ||||||
|  |  | ||||||
|  | // +build amd64,!gccgo,!appengine | ||||||
|  |  | ||||||
|  | #include "const_amd64.h" | ||||||
|  |  | ||||||
|  | // func square(out, in *[5]uint64) | ||||||
|  | TEXT ·square(SB),7,$0-16 | ||||||
|  | 	MOVQ out+0(FP), DI | ||||||
|  | 	MOVQ in+8(FP), SI | ||||||
|  |  | ||||||
|  | 	MOVQ 0(SI),AX | ||||||
|  | 	MULQ 0(SI) | ||||||
|  | 	MOVQ AX,CX | ||||||
|  | 	MOVQ DX,R8 | ||||||
|  | 	MOVQ 0(SI),AX | ||||||
|  | 	SHLQ $1,AX | ||||||
|  | 	MULQ 8(SI) | ||||||
|  | 	MOVQ AX,R9 | ||||||
|  | 	MOVQ DX,R10 | ||||||
|  | 	MOVQ 0(SI),AX | ||||||
|  | 	SHLQ $1,AX | ||||||
|  | 	MULQ 16(SI) | ||||||
|  | 	MOVQ AX,R11 | ||||||
|  | 	MOVQ DX,R12 | ||||||
|  | 	MOVQ 0(SI),AX | ||||||
|  | 	SHLQ $1,AX | ||||||
|  | 	MULQ 24(SI) | ||||||
|  | 	MOVQ AX,R13 | ||||||
|  | 	MOVQ DX,R14 | ||||||
|  | 	MOVQ 0(SI),AX | ||||||
|  | 	SHLQ $1,AX | ||||||
|  | 	MULQ 32(SI) | ||||||
|  | 	MOVQ AX,R15 | ||||||
|  | 	MOVQ DX,BX | ||||||
|  | 	MOVQ 8(SI),AX | ||||||
|  | 	MULQ 8(SI) | ||||||
|  | 	ADDQ AX,R11 | ||||||
|  | 	ADCQ DX,R12 | ||||||
|  | 	MOVQ 8(SI),AX | ||||||
|  | 	SHLQ $1,AX | ||||||
|  | 	MULQ 16(SI) | ||||||
|  | 	ADDQ AX,R13 | ||||||
|  | 	ADCQ DX,R14 | ||||||
|  | 	MOVQ 8(SI),AX | ||||||
|  | 	SHLQ $1,AX | ||||||
|  | 	MULQ 24(SI) | ||||||
|  | 	ADDQ AX,R15 | ||||||
|  | 	ADCQ DX,BX | ||||||
|  | 	MOVQ 8(SI),DX | ||||||
|  | 	IMUL3Q $38,DX,AX | ||||||
|  | 	MULQ 32(SI) | ||||||
|  | 	ADDQ AX,CX | ||||||
|  | 	ADCQ DX,R8 | ||||||
|  | 	MOVQ 16(SI),AX | ||||||
|  | 	MULQ 16(SI) | ||||||
|  | 	ADDQ AX,R15 | ||||||
|  | 	ADCQ DX,BX | ||||||
|  | 	MOVQ 16(SI),DX | ||||||
|  | 	IMUL3Q $38,DX,AX | ||||||
|  | 	MULQ 24(SI) | ||||||
|  | 	ADDQ AX,CX | ||||||
|  | 	ADCQ DX,R8 | ||||||
|  | 	MOVQ 16(SI),DX | ||||||
|  | 	IMUL3Q $38,DX,AX | ||||||
|  | 	MULQ 32(SI) | ||||||
|  | 	ADDQ AX,R9 | ||||||
|  | 	ADCQ DX,R10 | ||||||
|  | 	MOVQ 24(SI),DX | ||||||
|  | 	IMUL3Q $19,DX,AX | ||||||
|  | 	MULQ 24(SI) | ||||||
|  | 	ADDQ AX,R9 | ||||||
|  | 	ADCQ DX,R10 | ||||||
|  | 	MOVQ 24(SI),DX | ||||||
|  | 	IMUL3Q $38,DX,AX | ||||||
|  | 	MULQ 32(SI) | ||||||
|  | 	ADDQ AX,R11 | ||||||
|  | 	ADCQ DX,R12 | ||||||
|  | 	MOVQ 32(SI),DX | ||||||
|  | 	IMUL3Q $19,DX,AX | ||||||
|  | 	MULQ 32(SI) | ||||||
|  | 	ADDQ AX,R13 | ||||||
|  | 	ADCQ DX,R14 | ||||||
|  | 	MOVQ $REDMASK51,SI | ||||||
|  | 	SHLQ $13,R8:CX | ||||||
|  | 	ANDQ SI,CX | ||||||
|  | 	SHLQ $13,R10:R9 | ||||||
|  | 	ANDQ SI,R9 | ||||||
|  | 	ADDQ R8,R9 | ||||||
|  | 	SHLQ $13,R12:R11 | ||||||
|  | 	ANDQ SI,R11 | ||||||
|  | 	ADDQ R10,R11 | ||||||
|  | 	SHLQ $13,R14:R13 | ||||||
|  | 	ANDQ SI,R13 | ||||||
|  | 	ADDQ R12,R13 | ||||||
|  | 	SHLQ $13,BX:R15 | ||||||
|  | 	ANDQ SI,R15 | ||||||
|  | 	ADDQ R14,R15 | ||||||
|  | 	IMUL3Q $19,BX,DX | ||||||
|  | 	ADDQ DX,CX | ||||||
|  | 	MOVQ CX,DX | ||||||
|  | 	SHRQ $51,DX | ||||||
|  | 	ADDQ R9,DX | ||||||
|  | 	ANDQ SI,CX | ||||||
|  | 	MOVQ DX,R8 | ||||||
|  | 	SHRQ $51,DX | ||||||
|  | 	ADDQ R11,DX | ||||||
|  | 	ANDQ SI,R8 | ||||||
|  | 	MOVQ DX,R9 | ||||||
|  | 	SHRQ $51,DX | ||||||
|  | 	ADDQ R13,DX | ||||||
|  | 	ANDQ SI,R9 | ||||||
|  | 	MOVQ DX,AX | ||||||
|  | 	SHRQ $51,DX | ||||||
|  | 	ADDQ R15,DX | ||||||
|  | 	ANDQ SI,AX | ||||||
|  | 	MOVQ DX,R10 | ||||||
|  | 	SHRQ $51,DX | ||||||
|  | 	IMUL3Q $19,DX,DX | ||||||
|  | 	ADDQ DX,CX | ||||||
|  | 	ANDQ SI,R10 | ||||||
|  | 	MOVQ CX,0(DI) | ||||||
|  | 	MOVQ R8,8(DI) | ||||||
|  | 	MOVQ R9,16(DI) | ||||||
|  | 	MOVQ AX,24(DI) | ||||||
|  | 	MOVQ R10,32(DI) | ||||||
|  | 	RET | ||||||
							
								
								
									
										27
									
								
								vendor/golang.org/x/crypto/ed25519/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/golang.org/x/crypto/ed25519/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | Copyright (c) 2009 The Go Authors. All rights reserved. | ||||||
|  |  | ||||||
|  | Redistribution and use in source and binary forms, with or without | ||||||
|  | modification, are permitted provided that the following conditions are | ||||||
|  | met: | ||||||
|  |  | ||||||
|  |    * Redistributions of source code must retain the above copyright | ||||||
|  | notice, this list of conditions and the following disclaimer. | ||||||
|  |    * Redistributions in binary form must reproduce the above | ||||||
|  | copyright notice, this list of conditions and the following disclaimer | ||||||
|  | in the documentation and/or other materials provided with the | ||||||
|  | distribution. | ||||||
|  |    * Neither the name of Google Inc. nor the names of its | ||||||
|  | contributors may be used to endorse or promote products derived from | ||||||
|  | this software without specific prior written permission. | ||||||
|  |  | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
							
								
								
									
										181
									
								
								vendor/golang.org/x/crypto/ed25519/ed25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								vendor/golang.org/x/crypto/ed25519/ed25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | |||||||
|  | // Copyright 2016 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 ed25519 implements the Ed25519 signature algorithm. See | ||||||
|  | // https://ed25519.cr.yp.to/. | ||||||
|  | // | ||||||
|  | // These functions are also compatible with the “Ed25519” function defined in | ||||||
|  | // RFC 8032. | ||||||
|  | package ed25519 | ||||||
|  |  | ||||||
|  | // This code is a port of the public domain, “ref10” implementation of ed25519 | ||||||
|  | // from SUPERCOP. | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"crypto" | ||||||
|  | 	cryptorand "crypto/rand" | ||||||
|  | 	"crypto/sha512" | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | 	"strconv" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/crypto/ed25519/internal/edwards25519" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// PublicKeySize is the size, in bytes, of public keys as used in this package. | ||||||
|  | 	PublicKeySize = 32 | ||||||
|  | 	// PrivateKeySize is the size, in bytes, of private keys as used in this package. | ||||||
|  | 	PrivateKeySize = 64 | ||||||
|  | 	// SignatureSize is the size, in bytes, of signatures generated and verified by this package. | ||||||
|  | 	SignatureSize = 64 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // PublicKey is the type of Ed25519 public keys. | ||||||
|  | type PublicKey []byte | ||||||
|  |  | ||||||
|  | // PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer. | ||||||
|  | type PrivateKey []byte | ||||||
|  |  | ||||||
|  | // Public returns the PublicKey corresponding to priv. | ||||||
|  | func (priv PrivateKey) Public() crypto.PublicKey { | ||||||
|  | 	publicKey := make([]byte, PublicKeySize) | ||||||
|  | 	copy(publicKey, priv[32:]) | ||||||
|  | 	return PublicKey(publicKey) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Sign signs the given message with priv. | ||||||
|  | // Ed25519 performs two passes over messages to be signed and therefore cannot | ||||||
|  | // handle pre-hashed messages. Thus opts.HashFunc() must return zero to | ||||||
|  | // indicate the message hasn't been hashed. This can be achieved by passing | ||||||
|  | // crypto.Hash(0) as the value for opts. | ||||||
|  | func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) { | ||||||
|  | 	if opts.HashFunc() != crypto.Hash(0) { | ||||||
|  | 		return nil, errors.New("ed25519: cannot sign hashed message") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return Sign(priv, message), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GenerateKey generates a public/private key pair using entropy from rand. | ||||||
|  | // If rand is nil, crypto/rand.Reader will be used. | ||||||
|  | func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) { | ||||||
|  | 	if rand == nil { | ||||||
|  | 		rand = cryptorand.Reader | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	privateKey = make([]byte, PrivateKeySize) | ||||||
|  | 	publicKey = make([]byte, PublicKeySize) | ||||||
|  | 	_, err = io.ReadFull(rand, privateKey[:32]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	digest := sha512.Sum512(privateKey[:32]) | ||||||
|  | 	digest[0] &= 248 | ||||||
|  | 	digest[31] &= 127 | ||||||
|  | 	digest[31] |= 64 | ||||||
|  |  | ||||||
|  | 	var A edwards25519.ExtendedGroupElement | ||||||
|  | 	var hBytes [32]byte | ||||||
|  | 	copy(hBytes[:], digest[:]) | ||||||
|  | 	edwards25519.GeScalarMultBase(&A, &hBytes) | ||||||
|  | 	var publicKeyBytes [32]byte | ||||||
|  | 	A.ToBytes(&publicKeyBytes) | ||||||
|  |  | ||||||
|  | 	copy(privateKey[32:], publicKeyBytes[:]) | ||||||
|  | 	copy(publicKey, publicKeyBytes[:]) | ||||||
|  |  | ||||||
|  | 	return publicKey, privateKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Sign signs the message with privateKey and returns a signature. It will | ||||||
|  | // panic if len(privateKey) is not PrivateKeySize. | ||||||
|  | func Sign(privateKey PrivateKey, message []byte) []byte { | ||||||
|  | 	if l := len(privateKey); l != PrivateKeySize { | ||||||
|  | 		panic("ed25519: bad private key length: " + strconv.Itoa(l)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	h := sha512.New() | ||||||
|  | 	h.Write(privateKey[:32]) | ||||||
|  |  | ||||||
|  | 	var digest1, messageDigest, hramDigest [64]byte | ||||||
|  | 	var expandedSecretKey [32]byte | ||||||
|  | 	h.Sum(digest1[:0]) | ||||||
|  | 	copy(expandedSecretKey[:], digest1[:]) | ||||||
|  | 	expandedSecretKey[0] &= 248 | ||||||
|  | 	expandedSecretKey[31] &= 63 | ||||||
|  | 	expandedSecretKey[31] |= 64 | ||||||
|  |  | ||||||
|  | 	h.Reset() | ||||||
|  | 	h.Write(digest1[32:]) | ||||||
|  | 	h.Write(message) | ||||||
|  | 	h.Sum(messageDigest[:0]) | ||||||
|  |  | ||||||
|  | 	var messageDigestReduced [32]byte | ||||||
|  | 	edwards25519.ScReduce(&messageDigestReduced, &messageDigest) | ||||||
|  | 	var R edwards25519.ExtendedGroupElement | ||||||
|  | 	edwards25519.GeScalarMultBase(&R, &messageDigestReduced) | ||||||
|  |  | ||||||
|  | 	var encodedR [32]byte | ||||||
|  | 	R.ToBytes(&encodedR) | ||||||
|  |  | ||||||
|  | 	h.Reset() | ||||||
|  | 	h.Write(encodedR[:]) | ||||||
|  | 	h.Write(privateKey[32:]) | ||||||
|  | 	h.Write(message) | ||||||
|  | 	h.Sum(hramDigest[:0]) | ||||||
|  | 	var hramDigestReduced [32]byte | ||||||
|  | 	edwards25519.ScReduce(&hramDigestReduced, &hramDigest) | ||||||
|  |  | ||||||
|  | 	var s [32]byte | ||||||
|  | 	edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced) | ||||||
|  |  | ||||||
|  | 	signature := make([]byte, SignatureSize) | ||||||
|  | 	copy(signature[:], encodedR[:]) | ||||||
|  | 	copy(signature[32:], s[:]) | ||||||
|  |  | ||||||
|  | 	return signature | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Verify reports whether sig is a valid signature of message by publicKey. It | ||||||
|  | // will panic if len(publicKey) is not PublicKeySize. | ||||||
|  | func Verify(publicKey PublicKey, message, sig []byte) bool { | ||||||
|  | 	if l := len(publicKey); l != PublicKeySize { | ||||||
|  | 		panic("ed25519: bad public key length: " + strconv.Itoa(l)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(sig) != SignatureSize || sig[63]&224 != 0 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var A edwards25519.ExtendedGroupElement | ||||||
|  | 	var publicKeyBytes [32]byte | ||||||
|  | 	copy(publicKeyBytes[:], publicKey) | ||||||
|  | 	if !A.FromBytes(&publicKeyBytes) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	edwards25519.FeNeg(&A.X, &A.X) | ||||||
|  | 	edwards25519.FeNeg(&A.T, &A.T) | ||||||
|  |  | ||||||
|  | 	h := sha512.New() | ||||||
|  | 	h.Write(sig[:32]) | ||||||
|  | 	h.Write(publicKey[:]) | ||||||
|  | 	h.Write(message) | ||||||
|  | 	var digest [64]byte | ||||||
|  | 	h.Sum(digest[:0]) | ||||||
|  |  | ||||||
|  | 	var hReduced [32]byte | ||||||
|  | 	edwards25519.ScReduce(&hReduced, &digest) | ||||||
|  |  | ||||||
|  | 	var R edwards25519.ProjectiveGroupElement | ||||||
|  | 	var b [32]byte | ||||||
|  | 	copy(b[:], sig[32:]) | ||||||
|  | 	edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b) | ||||||
|  |  | ||||||
|  | 	var checkR [32]byte | ||||||
|  | 	R.ToBytes(&checkR) | ||||||
|  | 	return bytes.Equal(sig[:32], checkR[:]) | ||||||
|  | } | ||||||
							
								
								
									
										1422
									
								
								vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1422
									
								
								vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1771
									
								
								vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1771
									
								
								vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										27
									
								
								vendor/golang.org/x/crypto/ssh/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/golang.org/x/crypto/ssh/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | Copyright (c) 2009 The Go Authors. All rights reserved. | ||||||
|  |  | ||||||
|  | Redistribution and use in source and binary forms, with or without | ||||||
|  | modification, are permitted provided that the following conditions are | ||||||
|  | met: | ||||||
|  |  | ||||||
|  |    * Redistributions of source code must retain the above copyright | ||||||
|  | notice, this list of conditions and the following disclaimer. | ||||||
|  |    * Redistributions in binary form must reproduce the above | ||||||
|  | copyright notice, this list of conditions and the following disclaimer | ||||||
|  | in the documentation and/or other materials provided with the | ||||||
|  | distribution. | ||||||
|  |    * Neither the name of Google Inc. nor the names of its | ||||||
|  | contributors may be used to endorse or promote products derived from | ||||||
|  | this software without specific prior written permission. | ||||||
|  |  | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||||
|  | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||||
|  | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||||
|  | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||||
|  | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||||
|  | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||||
|  | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||||
|  | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
							
								
								
									
										683
									
								
								vendor/golang.org/x/crypto/ssh/agent/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										683
									
								
								vendor/golang.org/x/crypto/ssh/agent/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,683 @@ | |||||||
|  | // Copyright 2012 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 agent implements the ssh-agent protocol, and provides both | ||||||
|  | // a client and a server. The client can talk to a standard ssh-agent | ||||||
|  | // that uses UNIX sockets, and one could implement an alternative | ||||||
|  | // ssh-agent process using the sample server. | ||||||
|  | // | ||||||
|  | // References: | ||||||
|  | //  [PROTOCOL.agent]:    http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent?rev=HEAD | ||||||
|  | package agent // import "golang.org/x/crypto/ssh/agent" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"crypto/dsa" | ||||||
|  | 	"crypto/ecdsa" | ||||||
|  | 	"crypto/elliptic" | ||||||
|  | 	"crypto/rsa" | ||||||
|  | 	"encoding/base64" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"math/big" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/crypto/ed25519" | ||||||
|  | 	"golang.org/x/crypto/ssh" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Agent represents the capabilities of an ssh-agent. | ||||||
|  | type Agent interface { | ||||||
|  | 	// List returns the identities known to the agent. | ||||||
|  | 	List() ([]*Key, error) | ||||||
|  |  | ||||||
|  | 	// Sign has the agent sign the data using a protocol 2 key as defined | ||||||
|  | 	// in [PROTOCOL.agent] section 2.6.2. | ||||||
|  | 	Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) | ||||||
|  |  | ||||||
|  | 	// Add adds a private key to the agent. | ||||||
|  | 	Add(key AddedKey) error | ||||||
|  |  | ||||||
|  | 	// Remove removes all identities with the given public key. | ||||||
|  | 	Remove(key ssh.PublicKey) error | ||||||
|  |  | ||||||
|  | 	// RemoveAll removes all identities. | ||||||
|  | 	RemoveAll() error | ||||||
|  |  | ||||||
|  | 	// Lock locks the agent. Sign and Remove will fail, and List will empty an empty list. | ||||||
|  | 	Lock(passphrase []byte) error | ||||||
|  |  | ||||||
|  | 	// Unlock undoes the effect of Lock | ||||||
|  | 	Unlock(passphrase []byte) error | ||||||
|  |  | ||||||
|  | 	// Signers returns signers for all the known keys. | ||||||
|  | 	Signers() ([]ssh.Signer, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ConstraintExtension describes an optional constraint defined by users. | ||||||
|  | type ConstraintExtension struct { | ||||||
|  | 	// ExtensionName consist of a UTF-8 string suffixed by the | ||||||
|  | 	// implementation domain following the naming scheme defined | ||||||
|  | 	// in Section 4.2 of [RFC4251], e.g.  "foo@example.com". | ||||||
|  | 	ExtensionName string | ||||||
|  | 	// ExtensionDetails contains the actual content of the extended | ||||||
|  | 	// constraint. | ||||||
|  | 	ExtensionDetails []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // AddedKey describes an SSH key to be added to an Agent. | ||||||
|  | type AddedKey struct { | ||||||
|  | 	// PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey or | ||||||
|  | 	// *ecdsa.PrivateKey, which will be inserted into the agent. | ||||||
|  | 	PrivateKey interface{} | ||||||
|  | 	// Certificate, if not nil, is communicated to the agent and will be | ||||||
|  | 	// stored with the key. | ||||||
|  | 	Certificate *ssh.Certificate | ||||||
|  | 	// Comment is an optional, free-form string. | ||||||
|  | 	Comment string | ||||||
|  | 	// LifetimeSecs, if not zero, is the number of seconds that the | ||||||
|  | 	// agent will store the key for. | ||||||
|  | 	LifetimeSecs uint32 | ||||||
|  | 	// ConfirmBeforeUse, if true, requests that the agent confirm with the | ||||||
|  | 	// user before each use of this key. | ||||||
|  | 	ConfirmBeforeUse bool | ||||||
|  | 	// ConstraintExtensions are the experimental or private-use constraints | ||||||
|  | 	// defined by users. | ||||||
|  | 	ConstraintExtensions []ConstraintExtension | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // See [PROTOCOL.agent], section 3. | ||||||
|  | const ( | ||||||
|  | 	agentRequestV1Identities   = 1 | ||||||
|  | 	agentRemoveAllV1Identities = 9 | ||||||
|  |  | ||||||
|  | 	// 3.2 Requests from client to agent for protocol 2 key operations | ||||||
|  | 	agentAddIdentity         = 17 | ||||||
|  | 	agentRemoveIdentity      = 18 | ||||||
|  | 	agentRemoveAllIdentities = 19 | ||||||
|  | 	agentAddIDConstrained    = 25 | ||||||
|  |  | ||||||
|  | 	// 3.3 Key-type independent requests from client to agent | ||||||
|  | 	agentAddSmartcardKey            = 20 | ||||||
|  | 	agentRemoveSmartcardKey         = 21 | ||||||
|  | 	agentLock                       = 22 | ||||||
|  | 	agentUnlock                     = 23 | ||||||
|  | 	agentAddSmartcardKeyConstrained = 26 | ||||||
|  |  | ||||||
|  | 	// 3.7 Key constraint identifiers | ||||||
|  | 	agentConstrainLifetime  = 1 | ||||||
|  | 	agentConstrainConfirm   = 2 | ||||||
|  | 	agentConstrainExtension = 3 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // maxAgentResponseBytes is the maximum agent reply size that is accepted. This | ||||||
|  | // is a sanity check, not a limit in the spec. | ||||||
|  | const maxAgentResponseBytes = 16 << 20 | ||||||
|  |  | ||||||
|  | // Agent messages: | ||||||
|  | // These structures mirror the wire format of the corresponding ssh agent | ||||||
|  | // messages found in [PROTOCOL.agent]. | ||||||
|  |  | ||||||
|  | // 3.4 Generic replies from agent to client | ||||||
|  | const agentFailure = 5 | ||||||
|  |  | ||||||
|  | type failureAgentMsg struct{} | ||||||
|  |  | ||||||
|  | const agentSuccess = 6 | ||||||
|  |  | ||||||
|  | type successAgentMsg struct{} | ||||||
|  |  | ||||||
|  | // See [PROTOCOL.agent], section 2.5.2. | ||||||
|  | const agentRequestIdentities = 11 | ||||||
|  |  | ||||||
|  | type requestIdentitiesAgentMsg struct{} | ||||||
|  |  | ||||||
|  | // See [PROTOCOL.agent], section 2.5.2. | ||||||
|  | const agentIdentitiesAnswer = 12 | ||||||
|  |  | ||||||
|  | type identitiesAnswerAgentMsg struct { | ||||||
|  | 	NumKeys uint32 `sshtype:"12"` | ||||||
|  | 	Keys    []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // See [PROTOCOL.agent], section 2.6.2. | ||||||
|  | const agentSignRequest = 13 | ||||||
|  |  | ||||||
|  | type signRequestAgentMsg struct { | ||||||
|  | 	KeyBlob []byte `sshtype:"13"` | ||||||
|  | 	Data    []byte | ||||||
|  | 	Flags   uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // See [PROTOCOL.agent], section 2.6.2. | ||||||
|  |  | ||||||
|  | // 3.6 Replies from agent to client for protocol 2 key operations | ||||||
|  | const agentSignResponse = 14 | ||||||
|  |  | ||||||
|  | type signResponseAgentMsg struct { | ||||||
|  | 	SigBlob []byte `sshtype:"14"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type publicKey struct { | ||||||
|  | 	Format string | ||||||
|  | 	Rest   []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 3.7 Key constraint identifiers | ||||||
|  | type constrainLifetimeAgentMsg struct { | ||||||
|  | 	LifetimeSecs uint32 `sshtype:"1"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type constrainExtensionAgentMsg struct { | ||||||
|  | 	ExtensionName    string `sshtype:"3"` | ||||||
|  | 	ExtensionDetails []byte | ||||||
|  |  | ||||||
|  | 	// Rest is a field used for parsing, not part of message | ||||||
|  | 	Rest []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Key represents a protocol 2 public key as defined in | ||||||
|  | // [PROTOCOL.agent], section 2.5.2. | ||||||
|  | type Key struct { | ||||||
|  | 	Format  string | ||||||
|  | 	Blob    []byte | ||||||
|  | 	Comment string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func clientErr(err error) error { | ||||||
|  | 	return fmt.Errorf("agent: client error: %v", err) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // String returns the storage form of an agent key with the format, base64 | ||||||
|  | // encoded serialized key, and the comment if it is not empty. | ||||||
|  | func (k *Key) String() string { | ||||||
|  | 	s := string(k.Format) + " " + base64.StdEncoding.EncodeToString(k.Blob) | ||||||
|  |  | ||||||
|  | 	if k.Comment != "" { | ||||||
|  | 		s += " " + k.Comment | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return s | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Type returns the public key type. | ||||||
|  | func (k *Key) Type() string { | ||||||
|  | 	return k.Format | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Marshal returns key blob to satisfy the ssh.PublicKey interface. | ||||||
|  | func (k *Key) Marshal() []byte { | ||||||
|  | 	return k.Blob | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Verify satisfies the ssh.PublicKey interface. | ||||||
|  | func (k *Key) Verify(data []byte, sig *ssh.Signature) error { | ||||||
|  | 	pubKey, err := ssh.ParsePublicKey(k.Blob) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("agent: bad public key: %v", err) | ||||||
|  | 	} | ||||||
|  | 	return pubKey.Verify(data, sig) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type wireKey struct { | ||||||
|  | 	Format string | ||||||
|  | 	Rest   []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseKey(in []byte) (out *Key, rest []byte, err error) { | ||||||
|  | 	var record struct { | ||||||
|  | 		Blob    []byte | ||||||
|  | 		Comment string | ||||||
|  | 		Rest    []byte `ssh:"rest"` | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := ssh.Unmarshal(in, &record); err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var wk wireKey | ||||||
|  | 	if err := ssh.Unmarshal(record.Blob, &wk); err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &Key{ | ||||||
|  | 		Format:  wk.Format, | ||||||
|  | 		Blob:    record.Blob, | ||||||
|  | 		Comment: record.Comment, | ||||||
|  | 	}, record.Rest, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // client is a client for an ssh-agent process. | ||||||
|  | type client struct { | ||||||
|  | 	// conn is typically a *net.UnixConn | ||||||
|  | 	conn io.ReadWriter | ||||||
|  | 	// mu is used to prevent concurrent access to the agent | ||||||
|  | 	mu sync.Mutex | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewClient returns an Agent that talks to an ssh-agent process over | ||||||
|  | // the given connection. | ||||||
|  | func NewClient(rw io.ReadWriter) Agent { | ||||||
|  | 	return &client{conn: rw} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // call sends an RPC to the agent. On success, the reply is | ||||||
|  | // unmarshaled into reply and replyType is set to the first byte of | ||||||
|  | // the reply, which contains the type of the message. | ||||||
|  | func (c *client) call(req []byte) (reply interface{}, err error) { | ||||||
|  | 	c.mu.Lock() | ||||||
|  | 	defer c.mu.Unlock() | ||||||
|  |  | ||||||
|  | 	msg := make([]byte, 4+len(req)) | ||||||
|  | 	binary.BigEndian.PutUint32(msg, uint32(len(req))) | ||||||
|  | 	copy(msg[4:], req) | ||||||
|  | 	if _, err = c.conn.Write(msg); err != nil { | ||||||
|  | 		return nil, clientErr(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var respSizeBuf [4]byte | ||||||
|  | 	if _, err = io.ReadFull(c.conn, respSizeBuf[:]); err != nil { | ||||||
|  | 		return nil, clientErr(err) | ||||||
|  | 	} | ||||||
|  | 	respSize := binary.BigEndian.Uint32(respSizeBuf[:]) | ||||||
|  | 	if respSize > maxAgentResponseBytes { | ||||||
|  | 		return nil, clientErr(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	buf := make([]byte, respSize) | ||||||
|  | 	if _, err = io.ReadFull(c.conn, buf); err != nil { | ||||||
|  | 		return nil, clientErr(err) | ||||||
|  | 	} | ||||||
|  | 	reply, err = unmarshal(buf) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, clientErr(err) | ||||||
|  | 	} | ||||||
|  | 	return reply, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *client) simpleCall(req []byte) error { | ||||||
|  | 	resp, err := c.call(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if _, ok := resp.(*successAgentMsg); ok { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return errors.New("agent: failure") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *client) RemoveAll() error { | ||||||
|  | 	return c.simpleCall([]byte{agentRemoveAllIdentities}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *client) Remove(key ssh.PublicKey) error { | ||||||
|  | 	req := ssh.Marshal(&agentRemoveIdentityMsg{ | ||||||
|  | 		KeyBlob: key.Marshal(), | ||||||
|  | 	}) | ||||||
|  | 	return c.simpleCall(req) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *client) Lock(passphrase []byte) error { | ||||||
|  | 	req := ssh.Marshal(&agentLockMsg{ | ||||||
|  | 		Passphrase: passphrase, | ||||||
|  | 	}) | ||||||
|  | 	return c.simpleCall(req) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *client) Unlock(passphrase []byte) error { | ||||||
|  | 	req := ssh.Marshal(&agentUnlockMsg{ | ||||||
|  | 		Passphrase: passphrase, | ||||||
|  | 	}) | ||||||
|  | 	return c.simpleCall(req) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // List returns the identities known to the agent. | ||||||
|  | func (c *client) List() ([]*Key, error) { | ||||||
|  | 	// see [PROTOCOL.agent] section 2.5.2. | ||||||
|  | 	req := []byte{agentRequestIdentities} | ||||||
|  |  | ||||||
|  | 	msg, err := c.call(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch msg := msg.(type) { | ||||||
|  | 	case *identitiesAnswerAgentMsg: | ||||||
|  | 		if msg.NumKeys > maxAgentResponseBytes/8 { | ||||||
|  | 			return nil, errors.New("agent: too many keys in agent reply") | ||||||
|  | 		} | ||||||
|  | 		keys := make([]*Key, msg.NumKeys) | ||||||
|  | 		data := msg.Keys | ||||||
|  | 		for i := uint32(0); i < msg.NumKeys; i++ { | ||||||
|  | 			var key *Key | ||||||
|  | 			var err error | ||||||
|  | 			if key, data, err = parseKey(data); err != nil { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  | 			keys[i] = key | ||||||
|  | 		} | ||||||
|  | 		return keys, nil | ||||||
|  | 	case *failureAgentMsg: | ||||||
|  | 		return nil, errors.New("agent: failed to list keys") | ||||||
|  | 	} | ||||||
|  | 	panic("unreachable") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Sign has the agent sign the data using a protocol 2 key as defined | ||||||
|  | // in [PROTOCOL.agent] section 2.6.2. | ||||||
|  | func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { | ||||||
|  | 	req := ssh.Marshal(signRequestAgentMsg{ | ||||||
|  | 		KeyBlob: key.Marshal(), | ||||||
|  | 		Data:    data, | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	msg, err := c.call(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch msg := msg.(type) { | ||||||
|  | 	case *signResponseAgentMsg: | ||||||
|  | 		var sig ssh.Signature | ||||||
|  | 		if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return &sig, nil | ||||||
|  | 	case *failureAgentMsg: | ||||||
|  | 		return nil, errors.New("agent: failed to sign challenge") | ||||||
|  | 	} | ||||||
|  | 	panic("unreachable") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // unmarshal parses an agent message in packet, returning the parsed | ||||||
|  | // form and the message type of packet. | ||||||
|  | func unmarshal(packet []byte) (interface{}, error) { | ||||||
|  | 	if len(packet) < 1 { | ||||||
|  | 		return nil, errors.New("agent: empty packet") | ||||||
|  | 	} | ||||||
|  | 	var msg interface{} | ||||||
|  | 	switch packet[0] { | ||||||
|  | 	case agentFailure: | ||||||
|  | 		return new(failureAgentMsg), nil | ||||||
|  | 	case agentSuccess: | ||||||
|  | 		return new(successAgentMsg), nil | ||||||
|  | 	case agentIdentitiesAnswer: | ||||||
|  | 		msg = new(identitiesAnswerAgentMsg) | ||||||
|  | 	case agentSignResponse: | ||||||
|  | 		msg = new(signResponseAgentMsg) | ||||||
|  | 	case agentV1IdentitiesAnswer: | ||||||
|  | 		msg = new(agentV1IdentityMsg) | ||||||
|  | 	default: | ||||||
|  | 		return nil, fmt.Errorf("agent: unknown type tag %d", packet[0]) | ||||||
|  | 	} | ||||||
|  | 	if err := ssh.Unmarshal(packet, msg); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return msg, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type rsaKeyMsg struct { | ||||||
|  | 	Type        string `sshtype:"17|25"` | ||||||
|  | 	N           *big.Int | ||||||
|  | 	E           *big.Int | ||||||
|  | 	D           *big.Int | ||||||
|  | 	Iqmp        *big.Int // IQMP = Inverse Q Mod P | ||||||
|  | 	P           *big.Int | ||||||
|  | 	Q           *big.Int | ||||||
|  | 	Comments    string | ||||||
|  | 	Constraints []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type dsaKeyMsg struct { | ||||||
|  | 	Type        string `sshtype:"17|25"` | ||||||
|  | 	P           *big.Int | ||||||
|  | 	Q           *big.Int | ||||||
|  | 	G           *big.Int | ||||||
|  | 	Y           *big.Int | ||||||
|  | 	X           *big.Int | ||||||
|  | 	Comments    string | ||||||
|  | 	Constraints []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ecdsaKeyMsg struct { | ||||||
|  | 	Type        string `sshtype:"17|25"` | ||||||
|  | 	Curve       string | ||||||
|  | 	KeyBytes    []byte | ||||||
|  | 	D           *big.Int | ||||||
|  | 	Comments    string | ||||||
|  | 	Constraints []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ed25519KeyMsg struct { | ||||||
|  | 	Type        string `sshtype:"17|25"` | ||||||
|  | 	Pub         []byte | ||||||
|  | 	Priv        []byte | ||||||
|  | 	Comments    string | ||||||
|  | 	Constraints []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Insert adds a private key to the agent. | ||||||
|  | func (c *client) insertKey(s interface{}, comment string, constraints []byte) error { | ||||||
|  | 	var req []byte | ||||||
|  | 	switch k := s.(type) { | ||||||
|  | 	case *rsa.PrivateKey: | ||||||
|  | 		if len(k.Primes) != 2 { | ||||||
|  | 			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes)) | ||||||
|  | 		} | ||||||
|  | 		k.Precompute() | ||||||
|  | 		req = ssh.Marshal(rsaKeyMsg{ | ||||||
|  | 			Type:        ssh.KeyAlgoRSA, | ||||||
|  | 			N:           k.N, | ||||||
|  | 			E:           big.NewInt(int64(k.E)), | ||||||
|  | 			D:           k.D, | ||||||
|  | 			Iqmp:        k.Precomputed.Qinv, | ||||||
|  | 			P:           k.Primes[0], | ||||||
|  | 			Q:           k.Primes[1], | ||||||
|  | 			Comments:    comment, | ||||||
|  | 			Constraints: constraints, | ||||||
|  | 		}) | ||||||
|  | 	case *dsa.PrivateKey: | ||||||
|  | 		req = ssh.Marshal(dsaKeyMsg{ | ||||||
|  | 			Type:        ssh.KeyAlgoDSA, | ||||||
|  | 			P:           k.P, | ||||||
|  | 			Q:           k.Q, | ||||||
|  | 			G:           k.G, | ||||||
|  | 			Y:           k.Y, | ||||||
|  | 			X:           k.X, | ||||||
|  | 			Comments:    comment, | ||||||
|  | 			Constraints: constraints, | ||||||
|  | 		}) | ||||||
|  | 	case *ecdsa.PrivateKey: | ||||||
|  | 		nistID := fmt.Sprintf("nistp%d", k.Params().BitSize) | ||||||
|  | 		req = ssh.Marshal(ecdsaKeyMsg{ | ||||||
|  | 			Type:        "ecdsa-sha2-" + nistID, | ||||||
|  | 			Curve:       nistID, | ||||||
|  | 			KeyBytes:    elliptic.Marshal(k.Curve, k.X, k.Y), | ||||||
|  | 			D:           k.D, | ||||||
|  | 			Comments:    comment, | ||||||
|  | 			Constraints: constraints, | ||||||
|  | 		}) | ||||||
|  | 	case *ed25519.PrivateKey: | ||||||
|  | 		req = ssh.Marshal(ed25519KeyMsg{ | ||||||
|  | 			Type:        ssh.KeyAlgoED25519, | ||||||
|  | 			Pub:         []byte(*k)[32:], | ||||||
|  | 			Priv:        []byte(*k), | ||||||
|  | 			Comments:    comment, | ||||||
|  | 			Constraints: constraints, | ||||||
|  | 		}) | ||||||
|  | 	default: | ||||||
|  | 		return fmt.Errorf("agent: unsupported key type %T", s) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// if constraints are present then the message type needs to be changed. | ||||||
|  | 	if len(constraints) != 0 { | ||||||
|  | 		req[0] = agentAddIDConstrained | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	resp, err := c.call(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if _, ok := resp.(*successAgentMsg); ok { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return errors.New("agent: failure") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type rsaCertMsg struct { | ||||||
|  | 	Type        string `sshtype:"17|25"` | ||||||
|  | 	CertBytes   []byte | ||||||
|  | 	D           *big.Int | ||||||
|  | 	Iqmp        *big.Int // IQMP = Inverse Q Mod P | ||||||
|  | 	P           *big.Int | ||||||
|  | 	Q           *big.Int | ||||||
|  | 	Comments    string | ||||||
|  | 	Constraints []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type dsaCertMsg struct { | ||||||
|  | 	Type        string `sshtype:"17|25"` | ||||||
|  | 	CertBytes   []byte | ||||||
|  | 	X           *big.Int | ||||||
|  | 	Comments    string | ||||||
|  | 	Constraints []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ecdsaCertMsg struct { | ||||||
|  | 	Type        string `sshtype:"17|25"` | ||||||
|  | 	CertBytes   []byte | ||||||
|  | 	D           *big.Int | ||||||
|  | 	Comments    string | ||||||
|  | 	Constraints []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type ed25519CertMsg struct { | ||||||
|  | 	Type        string `sshtype:"17|25"` | ||||||
|  | 	CertBytes   []byte | ||||||
|  | 	Pub         []byte | ||||||
|  | 	Priv        []byte | ||||||
|  | 	Comments    string | ||||||
|  | 	Constraints []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Add adds a private key to the agent. If a certificate is given, | ||||||
|  | // that certificate is added instead as public key. | ||||||
|  | func (c *client) Add(key AddedKey) error { | ||||||
|  | 	var constraints []byte | ||||||
|  |  | ||||||
|  | 	if secs := key.LifetimeSecs; secs != 0 { | ||||||
|  | 		constraints = append(constraints, ssh.Marshal(constrainLifetimeAgentMsg{secs})...) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if key.ConfirmBeforeUse { | ||||||
|  | 		constraints = append(constraints, agentConstrainConfirm) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	cert := key.Certificate | ||||||
|  | 	if cert == nil { | ||||||
|  | 		return c.insertKey(key.PrivateKey, key.Comment, constraints) | ||||||
|  | 	} | ||||||
|  | 	return c.insertCert(key.PrivateKey, cert, key.Comment, constraints) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string, constraints []byte) error { | ||||||
|  | 	var req []byte | ||||||
|  | 	switch k := s.(type) { | ||||||
|  | 	case *rsa.PrivateKey: | ||||||
|  | 		if len(k.Primes) != 2 { | ||||||
|  | 			return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes)) | ||||||
|  | 		} | ||||||
|  | 		k.Precompute() | ||||||
|  | 		req = ssh.Marshal(rsaCertMsg{ | ||||||
|  | 			Type:        cert.Type(), | ||||||
|  | 			CertBytes:   cert.Marshal(), | ||||||
|  | 			D:           k.D, | ||||||
|  | 			Iqmp:        k.Precomputed.Qinv, | ||||||
|  | 			P:           k.Primes[0], | ||||||
|  | 			Q:           k.Primes[1], | ||||||
|  | 			Comments:    comment, | ||||||
|  | 			Constraints: constraints, | ||||||
|  | 		}) | ||||||
|  | 	case *dsa.PrivateKey: | ||||||
|  | 		req = ssh.Marshal(dsaCertMsg{ | ||||||
|  | 			Type:        cert.Type(), | ||||||
|  | 			CertBytes:   cert.Marshal(), | ||||||
|  | 			X:           k.X, | ||||||
|  | 			Comments:    comment, | ||||||
|  | 			Constraints: constraints, | ||||||
|  | 		}) | ||||||
|  | 	case *ecdsa.PrivateKey: | ||||||
|  | 		req = ssh.Marshal(ecdsaCertMsg{ | ||||||
|  | 			Type:        cert.Type(), | ||||||
|  | 			CertBytes:   cert.Marshal(), | ||||||
|  | 			D:           k.D, | ||||||
|  | 			Comments:    comment, | ||||||
|  | 			Constraints: constraints, | ||||||
|  | 		}) | ||||||
|  | 	case *ed25519.PrivateKey: | ||||||
|  | 		req = ssh.Marshal(ed25519CertMsg{ | ||||||
|  | 			Type:        cert.Type(), | ||||||
|  | 			CertBytes:   cert.Marshal(), | ||||||
|  | 			Pub:         []byte(*k)[32:], | ||||||
|  | 			Priv:        []byte(*k), | ||||||
|  | 			Comments:    comment, | ||||||
|  | 			Constraints: constraints, | ||||||
|  | 		}) | ||||||
|  | 	default: | ||||||
|  | 		return fmt.Errorf("agent: unsupported key type %T", s) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// if constraints are present then the message type needs to be changed. | ||||||
|  | 	if len(constraints) != 0 { | ||||||
|  | 		req[0] = agentAddIDConstrained | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	signer, err := ssh.NewSignerFromKey(s) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { | ||||||
|  | 		return errors.New("agent: signer and cert have different public key") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	resp, err := c.call(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if _, ok := resp.(*successAgentMsg); ok { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return errors.New("agent: failure") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Signers provides a callback for client authentication. | ||||||
|  | func (c *client) Signers() ([]ssh.Signer, error) { | ||||||
|  | 	keys, err := c.List() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var result []ssh.Signer | ||||||
|  | 	for _, k := range keys { | ||||||
|  | 		result = append(result, &agentKeyringSigner{c, k}) | ||||||
|  | 	} | ||||||
|  | 	return result, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type agentKeyringSigner struct { | ||||||
|  | 	agent *client | ||||||
|  | 	pub   ssh.PublicKey | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *agentKeyringSigner) PublicKey() ssh.PublicKey { | ||||||
|  | 	return s.pub | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) { | ||||||
|  | 	// The agent has its own entropy source, so the rand argument is ignored. | ||||||
|  | 	return s.agent.Sign(s.pub, data) | ||||||
|  | } | ||||||
							
								
								
									
										103
									
								
								vendor/golang.org/x/crypto/ssh/agent/forward.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vendor/golang.org/x/crypto/ssh/agent/forward.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | |||||||
|  | // Copyright 2014 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 agent | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | 	"net" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/crypto/ssh" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // RequestAgentForwarding sets up agent forwarding for the session. | ||||||
|  | // ForwardToAgent or ForwardToRemote should be called to route | ||||||
|  | // the authentication requests. | ||||||
|  | func RequestAgentForwarding(session *ssh.Session) error { | ||||||
|  | 	ok, err := session.SendRequest("auth-agent-req@openssh.com", true, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if !ok { | ||||||
|  | 		return errors.New("forwarding request denied") | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ForwardToAgent routes authentication requests to the given keyring. | ||||||
|  | func ForwardToAgent(client *ssh.Client, keyring Agent) error { | ||||||
|  | 	channels := client.HandleChannelOpen(channelType) | ||||||
|  | 	if channels == nil { | ||||||
|  | 		return errors.New("agent: already have handler for " + channelType) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	go func() { | ||||||
|  | 		for ch := range channels { | ||||||
|  | 			channel, reqs, err := ch.Accept() | ||||||
|  | 			if err != nil { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			go ssh.DiscardRequests(reqs) | ||||||
|  | 			go func() { | ||||||
|  | 				ServeAgent(keyring, channel) | ||||||
|  | 				channel.Close() | ||||||
|  | 			}() | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const channelType = "auth-agent@openssh.com" | ||||||
|  |  | ||||||
|  | // ForwardToRemote routes authentication requests to the ssh-agent | ||||||
|  | // process serving on the given unix socket. | ||||||
|  | func ForwardToRemote(client *ssh.Client, addr string) error { | ||||||
|  | 	channels := client.HandleChannelOpen(channelType) | ||||||
|  | 	if channels == nil { | ||||||
|  | 		return errors.New("agent: already have handler for " + channelType) | ||||||
|  | 	} | ||||||
|  | 	conn, err := net.Dial("unix", addr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	conn.Close() | ||||||
|  |  | ||||||
|  | 	go func() { | ||||||
|  | 		for ch := range channels { | ||||||
|  | 			channel, reqs, err := ch.Accept() | ||||||
|  | 			if err != nil { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			go ssh.DiscardRequests(reqs) | ||||||
|  | 			go forwardUnixSocket(channel, addr) | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func forwardUnixSocket(channel ssh.Channel, addr string) { | ||||||
|  | 	conn, err := net.Dial("unix", addr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var wg sync.WaitGroup | ||||||
|  | 	wg.Add(2) | ||||||
|  | 	go func() { | ||||||
|  | 		io.Copy(conn, channel) | ||||||
|  | 		conn.(*net.UnixConn).CloseWrite() | ||||||
|  | 		wg.Done() | ||||||
|  | 	}() | ||||||
|  | 	go func() { | ||||||
|  | 		io.Copy(channel, conn) | ||||||
|  | 		channel.CloseWrite() | ||||||
|  | 		wg.Done() | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	wg.Wait() | ||||||
|  | 	conn.Close() | ||||||
|  | 	channel.Close() | ||||||
|  | } | ||||||
							
								
								
									
										215
									
								
								vendor/golang.org/x/crypto/ssh/agent/keyring.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								vendor/golang.org/x/crypto/ssh/agent/keyring.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,215 @@ | |||||||
|  | // Copyright 2014 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 agent | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"crypto/subtle" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/crypto/ssh" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type privKey struct { | ||||||
|  | 	signer  ssh.Signer | ||||||
|  | 	comment string | ||||||
|  | 	expire  *time.Time | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type keyring struct { | ||||||
|  | 	mu   sync.Mutex | ||||||
|  | 	keys []privKey | ||||||
|  |  | ||||||
|  | 	locked     bool | ||||||
|  | 	passphrase []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var errLocked = errors.New("agent: locked") | ||||||
|  |  | ||||||
|  | // NewKeyring returns an Agent that holds keys in memory.  It is safe | ||||||
|  | // for concurrent use by multiple goroutines. | ||||||
|  | func NewKeyring() Agent { | ||||||
|  | 	return &keyring{} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RemoveAll removes all identities. | ||||||
|  | func (r *keyring) RemoveAll() error { | ||||||
|  | 	r.mu.Lock() | ||||||
|  | 	defer r.mu.Unlock() | ||||||
|  | 	if r.locked { | ||||||
|  | 		return errLocked | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r.keys = nil | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // removeLocked does the actual key removal. The caller must already be holding the | ||||||
|  | // keyring mutex. | ||||||
|  | func (r *keyring) removeLocked(want []byte) error { | ||||||
|  | 	found := false | ||||||
|  | 	for i := 0; i < len(r.keys); { | ||||||
|  | 		if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) { | ||||||
|  | 			found = true | ||||||
|  | 			r.keys[i] = r.keys[len(r.keys)-1] | ||||||
|  | 			r.keys = r.keys[:len(r.keys)-1] | ||||||
|  | 			continue | ||||||
|  | 		} else { | ||||||
|  | 			i++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !found { | ||||||
|  | 		return errors.New("agent: key not found") | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Remove removes all identities with the given public key. | ||||||
|  | func (r *keyring) Remove(key ssh.PublicKey) error { | ||||||
|  | 	r.mu.Lock() | ||||||
|  | 	defer r.mu.Unlock() | ||||||
|  | 	if r.locked { | ||||||
|  | 		return errLocked | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return r.removeLocked(key.Marshal()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Lock locks the agent. Sign and Remove will fail, and List will return an empty list. | ||||||
|  | func (r *keyring) Lock(passphrase []byte) error { | ||||||
|  | 	r.mu.Lock() | ||||||
|  | 	defer r.mu.Unlock() | ||||||
|  | 	if r.locked { | ||||||
|  | 		return errLocked | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r.locked = true | ||||||
|  | 	r.passphrase = passphrase | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Unlock undoes the effect of Lock | ||||||
|  | func (r *keyring) Unlock(passphrase []byte) error { | ||||||
|  | 	r.mu.Lock() | ||||||
|  | 	defer r.mu.Unlock() | ||||||
|  | 	if !r.locked { | ||||||
|  | 		return errors.New("agent: not locked") | ||||||
|  | 	} | ||||||
|  | 	if len(passphrase) != len(r.passphrase) || 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) { | ||||||
|  | 		return fmt.Errorf("agent: incorrect passphrase") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r.locked = false | ||||||
|  | 	r.passphrase = nil | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // expireKeysLocked removes expired keys from the keyring. If a key was added | ||||||
|  | // with a lifetimesecs contraint and seconds >= lifetimesecs seconds have | ||||||
|  | // ellapsed, it is removed. The caller *must* be holding the keyring mutex. | ||||||
|  | func (r *keyring) expireKeysLocked() { | ||||||
|  | 	for _, k := range r.keys { | ||||||
|  | 		if k.expire != nil && time.Now().After(*k.expire) { | ||||||
|  | 			r.removeLocked(k.signer.PublicKey().Marshal()) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // List returns the identities known to the agent. | ||||||
|  | func (r *keyring) List() ([]*Key, error) { | ||||||
|  | 	r.mu.Lock() | ||||||
|  | 	defer r.mu.Unlock() | ||||||
|  | 	if r.locked { | ||||||
|  | 		// section 2.7: locked agents return empty. | ||||||
|  | 		return nil, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r.expireKeysLocked() | ||||||
|  | 	var ids []*Key | ||||||
|  | 	for _, k := range r.keys { | ||||||
|  | 		pub := k.signer.PublicKey() | ||||||
|  | 		ids = append(ids, &Key{ | ||||||
|  | 			Format:  pub.Type(), | ||||||
|  | 			Blob:    pub.Marshal(), | ||||||
|  | 			Comment: k.comment}) | ||||||
|  | 	} | ||||||
|  | 	return ids, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Insert adds a private key to the keyring. If a certificate | ||||||
|  | // is given, that certificate is added as public key. Note that | ||||||
|  | // any constraints given are ignored. | ||||||
|  | func (r *keyring) Add(key AddedKey) error { | ||||||
|  | 	r.mu.Lock() | ||||||
|  | 	defer r.mu.Unlock() | ||||||
|  | 	if r.locked { | ||||||
|  | 		return errLocked | ||||||
|  | 	} | ||||||
|  | 	signer, err := ssh.NewSignerFromKey(key.PrivateKey) | ||||||
|  |  | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if cert := key.Certificate; cert != nil { | ||||||
|  | 		signer, err = ssh.NewCertSigner(cert, signer) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	p := privKey{ | ||||||
|  | 		signer:  signer, | ||||||
|  | 		comment: key.Comment, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if key.LifetimeSecs > 0 { | ||||||
|  | 		t := time.Now().Add(time.Duration(key.LifetimeSecs) * time.Second) | ||||||
|  | 		p.expire = &t | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r.keys = append(r.keys, p) | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Sign returns a signature for the data. | ||||||
|  | func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { | ||||||
|  | 	r.mu.Lock() | ||||||
|  | 	defer r.mu.Unlock() | ||||||
|  | 	if r.locked { | ||||||
|  | 		return nil, errLocked | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r.expireKeysLocked() | ||||||
|  | 	wanted := key.Marshal() | ||||||
|  | 	for _, k := range r.keys { | ||||||
|  | 		if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { | ||||||
|  | 			return k.signer.Sign(rand.Reader, data) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil, errors.New("not found") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Signers returns signers for all the known keys. | ||||||
|  | func (r *keyring) Signers() ([]ssh.Signer, error) { | ||||||
|  | 	r.mu.Lock() | ||||||
|  | 	defer r.mu.Unlock() | ||||||
|  | 	if r.locked { | ||||||
|  | 		return nil, errLocked | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r.expireKeysLocked() | ||||||
|  | 	s := make([]ssh.Signer, 0, len(r.keys)) | ||||||
|  | 	for _, k := range r.keys { | ||||||
|  | 		s = append(s, k.signer) | ||||||
|  | 	} | ||||||
|  | 	return s, nil | ||||||
|  | } | ||||||
							
								
								
									
										523
									
								
								vendor/golang.org/x/crypto/ssh/agent/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										523
									
								
								vendor/golang.org/x/crypto/ssh/agent/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,523 @@ | |||||||
|  | // Copyright 2012 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 agent | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"crypto/dsa" | ||||||
|  | 	"crypto/ecdsa" | ||||||
|  | 	"crypto/elliptic" | ||||||
|  | 	"crypto/rsa" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"log" | ||||||
|  | 	"math/big" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/crypto/ed25519" | ||||||
|  | 	"golang.org/x/crypto/ssh" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Server wraps an Agent and uses it to implement the agent side of | ||||||
|  | // the SSH-agent, wire protocol. | ||||||
|  | type server struct { | ||||||
|  | 	agent Agent | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *server) processRequestBytes(reqData []byte) []byte { | ||||||
|  | 	rep, err := s.processRequest(reqData) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if err != errLocked { | ||||||
|  | 			// TODO(hanwen): provide better logging interface? | ||||||
|  | 			log.Printf("agent %d: %v", reqData[0], err) | ||||||
|  | 		} | ||||||
|  | 		return []byte{agentFailure} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err == nil && rep == nil { | ||||||
|  | 		return []byte{agentSuccess} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ssh.Marshal(rep) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func marshalKey(k *Key) []byte { | ||||||
|  | 	var record struct { | ||||||
|  | 		Blob    []byte | ||||||
|  | 		Comment string | ||||||
|  | 	} | ||||||
|  | 	record.Blob = k.Marshal() | ||||||
|  | 	record.Comment = k.Comment | ||||||
|  |  | ||||||
|  | 	return ssh.Marshal(&record) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // See [PROTOCOL.agent], section 2.5.1. | ||||||
|  | const agentV1IdentitiesAnswer = 2 | ||||||
|  |  | ||||||
|  | type agentV1IdentityMsg struct { | ||||||
|  | 	Numkeys uint32 `sshtype:"2"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type agentRemoveIdentityMsg struct { | ||||||
|  | 	KeyBlob []byte `sshtype:"18"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type agentLockMsg struct { | ||||||
|  | 	Passphrase []byte `sshtype:"22"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type agentUnlockMsg struct { | ||||||
|  | 	Passphrase []byte `sshtype:"23"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *server) processRequest(data []byte) (interface{}, error) { | ||||||
|  | 	switch data[0] { | ||||||
|  | 	case agentRequestV1Identities: | ||||||
|  | 		return &agentV1IdentityMsg{0}, nil | ||||||
|  |  | ||||||
|  | 	case agentRemoveAllV1Identities: | ||||||
|  | 		return nil, nil | ||||||
|  |  | ||||||
|  | 	case agentRemoveIdentity: | ||||||
|  | 		var req agentRemoveIdentityMsg | ||||||
|  | 		if err := ssh.Unmarshal(data, &req); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var wk wireKey | ||||||
|  | 		if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob}) | ||||||
|  |  | ||||||
|  | 	case agentRemoveAllIdentities: | ||||||
|  | 		return nil, s.agent.RemoveAll() | ||||||
|  |  | ||||||
|  | 	case agentLock: | ||||||
|  | 		var req agentLockMsg | ||||||
|  | 		if err := ssh.Unmarshal(data, &req); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return nil, s.agent.Lock(req.Passphrase) | ||||||
|  |  | ||||||
|  | 	case agentUnlock: | ||||||
|  | 		var req agentUnlockMsg | ||||||
|  | 		if err := ssh.Unmarshal(data, &req); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		return nil, s.agent.Unlock(req.Passphrase) | ||||||
|  |  | ||||||
|  | 	case agentSignRequest: | ||||||
|  | 		var req signRequestAgentMsg | ||||||
|  | 		if err := ssh.Unmarshal(data, &req); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var wk wireKey | ||||||
|  | 		if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		k := &Key{ | ||||||
|  | 			Format: wk.Format, | ||||||
|  | 			Blob:   req.KeyBlob, | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		sig, err := s.agent.Sign(k, req.Data) //  TODO(hanwen): flags. | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil | ||||||
|  |  | ||||||
|  | 	case agentRequestIdentities: | ||||||
|  | 		keys, err := s.agent.List() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		rep := identitiesAnswerAgentMsg{ | ||||||
|  | 			NumKeys: uint32(len(keys)), | ||||||
|  | 		} | ||||||
|  | 		for _, k := range keys { | ||||||
|  | 			rep.Keys = append(rep.Keys, marshalKey(k)...) | ||||||
|  | 		} | ||||||
|  | 		return rep, nil | ||||||
|  |  | ||||||
|  | 	case agentAddIDConstrained, agentAddIdentity: | ||||||
|  | 		return nil, s.insertIdentity(data) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil, fmt.Errorf("unknown opcode %d", data[0]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseConstraints(constraints []byte) (lifetimeSecs uint32, confirmBeforeUse bool, extensions []ConstraintExtension, err error) { | ||||||
|  | 	for len(constraints) != 0 { | ||||||
|  | 		switch constraints[0] { | ||||||
|  | 		case agentConstrainLifetime: | ||||||
|  | 			lifetimeSecs = binary.BigEndian.Uint32(constraints[1:5]) | ||||||
|  | 			constraints = constraints[5:] | ||||||
|  | 		case agentConstrainConfirm: | ||||||
|  | 			confirmBeforeUse = true | ||||||
|  | 			constraints = constraints[1:] | ||||||
|  | 		case agentConstrainExtension: | ||||||
|  | 			var msg constrainExtensionAgentMsg | ||||||
|  | 			if err = ssh.Unmarshal(constraints, &msg); err != nil { | ||||||
|  | 				return 0, false, nil, err | ||||||
|  | 			} | ||||||
|  | 			extensions = append(extensions, ConstraintExtension{ | ||||||
|  | 				ExtensionName:    msg.ExtensionName, | ||||||
|  | 				ExtensionDetails: msg.ExtensionDetails, | ||||||
|  | 			}) | ||||||
|  | 			constraints = msg.Rest | ||||||
|  | 		default: | ||||||
|  | 			return 0, false, nil, fmt.Errorf("unknown constraint type: %d", constraints[0]) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func setConstraints(key *AddedKey, constraintBytes []byte) error { | ||||||
|  | 	lifetimeSecs, confirmBeforeUse, constraintExtensions, err := parseConstraints(constraintBytes) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	key.LifetimeSecs = lifetimeSecs | ||||||
|  | 	key.ConfirmBeforeUse = confirmBeforeUse | ||||||
|  | 	key.ConstraintExtensions = constraintExtensions | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseRSAKey(req []byte) (*AddedKey, error) { | ||||||
|  | 	var k rsaKeyMsg | ||||||
|  | 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if k.E.BitLen() > 30 { | ||||||
|  | 		return nil, errors.New("agent: RSA public exponent too large") | ||||||
|  | 	} | ||||||
|  | 	priv := &rsa.PrivateKey{ | ||||||
|  | 		PublicKey: rsa.PublicKey{ | ||||||
|  | 			E: int(k.E.Int64()), | ||||||
|  | 			N: k.N, | ||||||
|  | 		}, | ||||||
|  | 		D:      k.D, | ||||||
|  | 		Primes: []*big.Int{k.P, k.Q}, | ||||||
|  | 	} | ||||||
|  | 	priv.Precompute() | ||||||
|  |  | ||||||
|  | 	addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} | ||||||
|  | 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return addedKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseEd25519Key(req []byte) (*AddedKey, error) { | ||||||
|  | 	var k ed25519KeyMsg | ||||||
|  | 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	priv := ed25519.PrivateKey(k.Priv) | ||||||
|  |  | ||||||
|  | 	addedKey := &AddedKey{PrivateKey: &priv, Comment: k.Comments} | ||||||
|  | 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return addedKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseDSAKey(req []byte) (*AddedKey, error) { | ||||||
|  | 	var k dsaKeyMsg | ||||||
|  | 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	priv := &dsa.PrivateKey{ | ||||||
|  | 		PublicKey: dsa.PublicKey{ | ||||||
|  | 			Parameters: dsa.Parameters{ | ||||||
|  | 				P: k.P, | ||||||
|  | 				Q: k.Q, | ||||||
|  | 				G: k.G, | ||||||
|  | 			}, | ||||||
|  | 			Y: k.Y, | ||||||
|  | 		}, | ||||||
|  | 		X: k.X, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} | ||||||
|  | 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return addedKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func unmarshalECDSA(curveName string, keyBytes []byte, privScalar *big.Int) (priv *ecdsa.PrivateKey, err error) { | ||||||
|  | 	priv = &ecdsa.PrivateKey{ | ||||||
|  | 		D: privScalar, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch curveName { | ||||||
|  | 	case "nistp256": | ||||||
|  | 		priv.Curve = elliptic.P256() | ||||||
|  | 	case "nistp384": | ||||||
|  | 		priv.Curve = elliptic.P384() | ||||||
|  | 	case "nistp521": | ||||||
|  | 		priv.Curve = elliptic.P521() | ||||||
|  | 	default: | ||||||
|  | 		return nil, fmt.Errorf("agent: unknown curve %q", curveName) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	priv.X, priv.Y = elliptic.Unmarshal(priv.Curve, keyBytes) | ||||||
|  | 	if priv.X == nil || priv.Y == nil { | ||||||
|  | 		return nil, errors.New("agent: point not on curve") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return priv, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseEd25519Cert(req []byte) (*AddedKey, error) { | ||||||
|  | 	var k ed25519CertMsg | ||||||
|  | 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	pubKey, err := ssh.ParsePublicKey(k.CertBytes) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	priv := ed25519.PrivateKey(k.Priv) | ||||||
|  | 	cert, ok := pubKey.(*ssh.Certificate) | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, errors.New("agent: bad ED25519 certificate") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments} | ||||||
|  | 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return addedKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseECDSAKey(req []byte) (*AddedKey, error) { | ||||||
|  | 	var k ecdsaKeyMsg | ||||||
|  | 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	priv, err := unmarshalECDSA(k.Curve, k.KeyBytes, k.D) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	addedKey := &AddedKey{PrivateKey: priv, Comment: k.Comments} | ||||||
|  | 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return addedKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseRSACert(req []byte) (*AddedKey, error) { | ||||||
|  | 	var k rsaCertMsg | ||||||
|  | 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pubKey, err := ssh.ParsePublicKey(k.CertBytes) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	cert, ok := pubKey.(*ssh.Certificate) | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, errors.New("agent: bad RSA certificate") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// An RSA publickey as marshaled by rsaPublicKey.Marshal() in keys.go | ||||||
|  | 	var rsaPub struct { | ||||||
|  | 		Name string | ||||||
|  | 		E    *big.Int | ||||||
|  | 		N    *big.Int | ||||||
|  | 	} | ||||||
|  | 	if err := ssh.Unmarshal(cert.Key.Marshal(), &rsaPub); err != nil { | ||||||
|  | 		return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if rsaPub.E.BitLen() > 30 { | ||||||
|  | 		return nil, errors.New("agent: RSA public exponent too large") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	priv := rsa.PrivateKey{ | ||||||
|  | 		PublicKey: rsa.PublicKey{ | ||||||
|  | 			E: int(rsaPub.E.Int64()), | ||||||
|  | 			N: rsaPub.N, | ||||||
|  | 		}, | ||||||
|  | 		D:      k.D, | ||||||
|  | 		Primes: []*big.Int{k.Q, k.P}, | ||||||
|  | 	} | ||||||
|  | 	priv.Precompute() | ||||||
|  |  | ||||||
|  | 	addedKey := &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments} | ||||||
|  | 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return addedKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseDSACert(req []byte) (*AddedKey, error) { | ||||||
|  | 	var k dsaCertMsg | ||||||
|  | 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	pubKey, err := ssh.ParsePublicKey(k.CertBytes) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	cert, ok := pubKey.(*ssh.Certificate) | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, errors.New("agent: bad DSA certificate") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// A DSA publickey as marshaled by dsaPublicKey.Marshal() in keys.go | ||||||
|  | 	var w struct { | ||||||
|  | 		Name       string | ||||||
|  | 		P, Q, G, Y *big.Int | ||||||
|  | 	} | ||||||
|  | 	if err := ssh.Unmarshal(cert.Key.Marshal(), &w); err != nil { | ||||||
|  | 		return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	priv := &dsa.PrivateKey{ | ||||||
|  | 		PublicKey: dsa.PublicKey{ | ||||||
|  | 			Parameters: dsa.Parameters{ | ||||||
|  | 				P: w.P, | ||||||
|  | 				Q: w.Q, | ||||||
|  | 				G: w.G, | ||||||
|  | 			}, | ||||||
|  | 			Y: w.Y, | ||||||
|  | 		}, | ||||||
|  | 		X: k.X, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments} | ||||||
|  | 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return addedKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseECDSACert(req []byte) (*AddedKey, error) { | ||||||
|  | 	var k ecdsaCertMsg | ||||||
|  | 	if err := ssh.Unmarshal(req, &k); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pubKey, err := ssh.ParsePublicKey(k.CertBytes) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	cert, ok := pubKey.(*ssh.Certificate) | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, errors.New("agent: bad ECDSA certificate") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// An ECDSA publickey as marshaled by ecdsaPublicKey.Marshal() in keys.go | ||||||
|  | 	var ecdsaPub struct { | ||||||
|  | 		Name string | ||||||
|  | 		ID   string | ||||||
|  | 		Key  []byte | ||||||
|  | 	} | ||||||
|  | 	if err := ssh.Unmarshal(cert.Key.Marshal(), &ecdsaPub); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	priv, err := unmarshalECDSA(ecdsaPub.ID, ecdsaPub.Key, k.D) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	addedKey := &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments} | ||||||
|  | 	if err := setConstraints(addedKey, k.Constraints); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return addedKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *server) insertIdentity(req []byte) error { | ||||||
|  | 	var record struct { | ||||||
|  | 		Type string `sshtype:"17|25"` | ||||||
|  | 		Rest []byte `ssh:"rest"` | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := ssh.Unmarshal(req, &record); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var addedKey *AddedKey | ||||||
|  | 	var err error | ||||||
|  |  | ||||||
|  | 	switch record.Type { | ||||||
|  | 	case ssh.KeyAlgoRSA: | ||||||
|  | 		addedKey, err = parseRSAKey(req) | ||||||
|  | 	case ssh.KeyAlgoDSA: | ||||||
|  | 		addedKey, err = parseDSAKey(req) | ||||||
|  | 	case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521: | ||||||
|  | 		addedKey, err = parseECDSAKey(req) | ||||||
|  | 	case ssh.KeyAlgoED25519: | ||||||
|  | 		addedKey, err = parseEd25519Key(req) | ||||||
|  | 	case ssh.CertAlgoRSAv01: | ||||||
|  | 		addedKey, err = parseRSACert(req) | ||||||
|  | 	case ssh.CertAlgoDSAv01: | ||||||
|  | 		addedKey, err = parseDSACert(req) | ||||||
|  | 	case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01: | ||||||
|  | 		addedKey, err = parseECDSACert(req) | ||||||
|  | 	case ssh.CertAlgoED25519v01: | ||||||
|  | 		addedKey, err = parseEd25519Cert(req) | ||||||
|  | 	default: | ||||||
|  | 		return fmt.Errorf("agent: not implemented: %q", record.Type) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return s.agent.Add(*addedKey) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ServeAgent serves the agent protocol on the given connection. It | ||||||
|  | // returns when an I/O error occurs. | ||||||
|  | func ServeAgent(agent Agent, c io.ReadWriter) error { | ||||||
|  | 	s := &server{agent} | ||||||
|  |  | ||||||
|  | 	var length [4]byte | ||||||
|  | 	for { | ||||||
|  | 		if _, err := io.ReadFull(c, length[:]); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		l := binary.BigEndian.Uint32(length[:]) | ||||||
|  | 		if l > maxAgentResponseBytes { | ||||||
|  | 			// We also cap requests. | ||||||
|  | 			return fmt.Errorf("agent: request too large: %d", l) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		req := make([]byte, l) | ||||||
|  | 		if _, err := io.ReadFull(c, req); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		repData := s.processRequestBytes(req) | ||||||
|  | 		if len(repData) > maxAgentResponseBytes { | ||||||
|  | 			return fmt.Errorf("agent: reply too large: %d bytes", len(repData)) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		binary.BigEndian.PutUint32(length[:], uint32(len(repData))) | ||||||
|  | 		if _, err := c.Write(length[:]); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if _, err := c.Write(repData); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										97
									
								
								vendor/golang.org/x/crypto/ssh/buffer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								vendor/golang.org/x/crypto/ssh/buffer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | |||||||
|  | // Copyright 2012 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 ( | ||||||
|  | 	"io" | ||||||
|  | 	"sync" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // buffer provides a linked list buffer for data exchange | ||||||
|  | // between producer and consumer. Theoretically the buffer is | ||||||
|  | // of unlimited capacity as it does no allocation of its own. | ||||||
|  | type buffer struct { | ||||||
|  | 	// protects concurrent access to head, tail and closed | ||||||
|  | 	*sync.Cond | ||||||
|  |  | ||||||
|  | 	head *element // the buffer that will be read first | ||||||
|  | 	tail *element // the buffer that will be read last | ||||||
|  |  | ||||||
|  | 	closed bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // An element represents a single link in a linked list. | ||||||
|  | type element struct { | ||||||
|  | 	buf  []byte | ||||||
|  | 	next *element | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // newBuffer returns an empty buffer that is not closed. | ||||||
|  | func newBuffer() *buffer { | ||||||
|  | 	e := new(element) | ||||||
|  | 	b := &buffer{ | ||||||
|  | 		Cond: newCond(), | ||||||
|  | 		head: e, | ||||||
|  | 		tail: e, | ||||||
|  | 	} | ||||||
|  | 	return b | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // write makes buf available for Read to receive. | ||||||
|  | // buf must not be modified after the call to write. | ||||||
|  | func (b *buffer) write(buf []byte) { | ||||||
|  | 	b.Cond.L.Lock() | ||||||
|  | 	e := &element{buf: buf} | ||||||
|  | 	b.tail.next = e | ||||||
|  | 	b.tail = e | ||||||
|  | 	b.Cond.Signal() | ||||||
|  | 	b.Cond.L.Unlock() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // eof closes the buffer. Reads from the buffer once all | ||||||
|  | // the data has been consumed will receive io.EOF. | ||||||
|  | func (b *buffer) eof() { | ||||||
|  | 	b.Cond.L.Lock() | ||||||
|  | 	b.closed = true | ||||||
|  | 	b.Cond.Signal() | ||||||
|  | 	b.Cond.L.Unlock() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Read reads data from the internal buffer in buf.  Reads will block | ||||||
|  | // if no data is available, or until the buffer is closed. | ||||||
|  | func (b *buffer) Read(buf []byte) (n int, err error) { | ||||||
|  | 	b.Cond.L.Lock() | ||||||
|  | 	defer b.Cond.L.Unlock() | ||||||
|  |  | ||||||
|  | 	for len(buf) > 0 { | ||||||
|  | 		// if there is data in b.head, copy it | ||||||
|  | 		if len(b.head.buf) > 0 { | ||||||
|  | 			r := copy(buf, b.head.buf) | ||||||
|  | 			buf, b.head.buf = buf[r:], b.head.buf[r:] | ||||||
|  | 			n += r | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		// if there is a next buffer, make it the head | ||||||
|  | 		if len(b.head.buf) == 0 && b.head != b.tail { | ||||||
|  | 			b.head = b.head.next | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// if at least one byte has been copied, return | ||||||
|  | 		if n > 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// if nothing was read, and there is nothing outstanding | ||||||
|  | 		// check to see if the buffer is closed. | ||||||
|  | 		if b.closed { | ||||||
|  | 			err = io.EOF | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		// out of buffers, wait for producer | ||||||
|  | 		b.Cond.Wait() | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
							
								
								
									
										519
									
								
								vendor/golang.org/x/crypto/ssh/certs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										519
									
								
								vendor/golang.org/x/crypto/ssh/certs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,519 @@ | |||||||
|  | // Copyright 2012 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" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"net" | ||||||
|  | 	"sort" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // These constants from [PROTOCOL.certkeys] represent the algorithm names | ||||||
|  | // for certificate types supported by this package. | ||||||
|  | const ( | ||||||
|  | 	CertAlgoRSAv01      = "ssh-rsa-cert-v01@openssh.com" | ||||||
|  | 	CertAlgoDSAv01      = "ssh-dss-cert-v01@openssh.com" | ||||||
|  | 	CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com" | ||||||
|  | 	CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com" | ||||||
|  | 	CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com" | ||||||
|  | 	CertAlgoED25519v01  = "ssh-ed25519-cert-v01@openssh.com" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Certificate types distinguish between host and user | ||||||
|  | // certificates. The values can be set in the CertType field of | ||||||
|  | // Certificate. | ||||||
|  | const ( | ||||||
|  | 	UserCert = 1 | ||||||
|  | 	HostCert = 2 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Signature represents a cryptographic signature. | ||||||
|  | type Signature struct { | ||||||
|  | 	Format string | ||||||
|  | 	Blob   []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that | ||||||
|  | // a certificate does not expire. | ||||||
|  | const CertTimeInfinity = 1<<64 - 1 | ||||||
|  |  | ||||||
|  | // An Certificate represents an OpenSSH certificate as defined in | ||||||
|  | // [PROTOCOL.certkeys]?rev=1.8. | ||||||
|  | type Certificate struct { | ||||||
|  | 	Nonce           []byte | ||||||
|  | 	Key             PublicKey | ||||||
|  | 	Serial          uint64 | ||||||
|  | 	CertType        uint32 | ||||||
|  | 	KeyId           string | ||||||
|  | 	ValidPrincipals []string | ||||||
|  | 	ValidAfter      uint64 | ||||||
|  | 	ValidBefore     uint64 | ||||||
|  | 	Permissions | ||||||
|  | 	Reserved     []byte | ||||||
|  | 	SignatureKey PublicKey | ||||||
|  | 	Signature    *Signature | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // genericCertData holds the key-independent part of the certificate data. | ||||||
|  | // Overall, certificates contain an nonce, public key fields and | ||||||
|  | // key-independent fields. | ||||||
|  | type genericCertData struct { | ||||||
|  | 	Serial          uint64 | ||||||
|  | 	CertType        uint32 | ||||||
|  | 	KeyId           string | ||||||
|  | 	ValidPrincipals []byte | ||||||
|  | 	ValidAfter      uint64 | ||||||
|  | 	ValidBefore     uint64 | ||||||
|  | 	CriticalOptions []byte | ||||||
|  | 	Extensions      []byte | ||||||
|  | 	Reserved        []byte | ||||||
|  | 	SignatureKey    []byte | ||||||
|  | 	Signature       []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func marshalStringList(namelist []string) []byte { | ||||||
|  | 	var to []byte | ||||||
|  | 	for _, name := range namelist { | ||||||
|  | 		s := struct{ N string }{name} | ||||||
|  | 		to = append(to, Marshal(&s)...) | ||||||
|  | 	} | ||||||
|  | 	return to | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type optionsTuple struct { | ||||||
|  | 	Key   string | ||||||
|  | 	Value []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type optionsTupleValue struct { | ||||||
|  | 	Value string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // serialize a map of critical options or extensions | ||||||
|  | // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, | ||||||
|  | // we need two length prefixes for a non-empty string value | ||||||
|  | func marshalTuples(tups map[string]string) []byte { | ||||||
|  | 	keys := make([]string, 0, len(tups)) | ||||||
|  | 	for key := range tups { | ||||||
|  | 		keys = append(keys, key) | ||||||
|  | 	} | ||||||
|  | 	sort.Strings(keys) | ||||||
|  |  | ||||||
|  | 	var ret []byte | ||||||
|  | 	for _, key := range keys { | ||||||
|  | 		s := optionsTuple{Key: key} | ||||||
|  | 		if value := tups[key]; len(value) > 0 { | ||||||
|  | 			s.Value = Marshal(&optionsTupleValue{value}) | ||||||
|  | 		} | ||||||
|  | 		ret = append(ret, Marshal(&s)...) | ||||||
|  | 	} | ||||||
|  | 	return ret | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, | ||||||
|  | // we need two length prefixes for a non-empty option value | ||||||
|  | func parseTuples(in []byte) (map[string]string, error) { | ||||||
|  | 	tups := map[string]string{} | ||||||
|  | 	var lastKey string | ||||||
|  | 	var haveLastKey bool | ||||||
|  |  | ||||||
|  | 	for len(in) > 0 { | ||||||
|  | 		var key, val, extra []byte | ||||||
|  | 		var ok bool | ||||||
|  |  | ||||||
|  | 		if key, in, ok = parseString(in); !ok { | ||||||
|  | 			return nil, errShortRead | ||||||
|  | 		} | ||||||
|  | 		keyStr := string(key) | ||||||
|  | 		// according to [PROTOCOL.certkeys], the names must be in | ||||||
|  | 		// lexical order. | ||||||
|  | 		if haveLastKey && keyStr <= lastKey { | ||||||
|  | 			return nil, fmt.Errorf("ssh: certificate options are not in lexical order") | ||||||
|  | 		} | ||||||
|  | 		lastKey, haveLastKey = keyStr, true | ||||||
|  | 		// the next field is a data field, which if non-empty has a string embedded | ||||||
|  | 		if val, in, ok = parseString(in); !ok { | ||||||
|  | 			return nil, errShortRead | ||||||
|  | 		} | ||||||
|  | 		if len(val) > 0 { | ||||||
|  | 			val, extra, ok = parseString(val) | ||||||
|  | 			if !ok { | ||||||
|  | 				return nil, errShortRead | ||||||
|  | 			} | ||||||
|  | 			if len(extra) > 0 { | ||||||
|  | 				return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value") | ||||||
|  | 			} | ||||||
|  | 			tups[keyStr] = string(val) | ||||||
|  | 		} else { | ||||||
|  | 			tups[keyStr] = "" | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return tups, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseCert(in []byte, privAlgo string) (*Certificate, error) { | ||||||
|  | 	nonce, rest, ok := parseString(in) | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, errShortRead | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	key, rest, err := parsePubKey(rest, privAlgo) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var g genericCertData | ||||||
|  | 	if err := Unmarshal(rest, &g); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c := &Certificate{ | ||||||
|  | 		Nonce:       nonce, | ||||||
|  | 		Key:         key, | ||||||
|  | 		Serial:      g.Serial, | ||||||
|  | 		CertType:    g.CertType, | ||||||
|  | 		KeyId:       g.KeyId, | ||||||
|  | 		ValidAfter:  g.ValidAfter, | ||||||
|  | 		ValidBefore: g.ValidBefore, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for principals := g.ValidPrincipals; len(principals) > 0; { | ||||||
|  | 		principal, rest, ok := parseString(principals) | ||||||
|  | 		if !ok { | ||||||
|  | 			return nil, errShortRead | ||||||
|  | 		} | ||||||
|  | 		c.ValidPrincipals = append(c.ValidPrincipals, string(principal)) | ||||||
|  | 		principals = rest | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c.CriticalOptions, err = parseTuples(g.CriticalOptions) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	c.Extensions, err = parseTuples(g.Extensions) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	c.Reserved = g.Reserved | ||||||
|  | 	k, err := ParsePublicKey(g.SignatureKey) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c.SignatureKey = k | ||||||
|  | 	c.Signature, rest, ok = parseSignatureBody(g.Signature) | ||||||
|  | 	if !ok || len(rest) > 0 { | ||||||
|  | 		return nil, errors.New("ssh: signature parse error") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return c, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type openSSHCertSigner struct { | ||||||
|  | 	pub    *Certificate | ||||||
|  | 	signer Signer | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewCertSigner returns a Signer that signs with the given Certificate, whose | ||||||
|  | // private key is held by signer. It returns an error if the public key in cert | ||||||
|  | // doesn't match the key used by signer. | ||||||
|  | func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { | ||||||
|  | 	if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { | ||||||
|  | 		return nil, errors.New("ssh: signer and cert have different public key") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &openSSHCertSigner{cert, signer}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { | ||||||
|  | 	return s.signer.Sign(rand, data) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *openSSHCertSigner) PublicKey() PublicKey { | ||||||
|  | 	return s.pub | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const sourceAddressCriticalOption = "source-address" | ||||||
|  |  | ||||||
|  | // CertChecker does the work of verifying a certificate. Its methods | ||||||
|  | // can be plugged into ClientConfig.HostKeyCallback and | ||||||
|  | // ServerConfig.PublicKeyCallback. For the CertChecker to work, | ||||||
|  | // minimally, the IsAuthority callback should be set. | ||||||
|  | type CertChecker struct { | ||||||
|  | 	// SupportedCriticalOptions lists the CriticalOptions that the | ||||||
|  | 	// server application layer understands. These are only used | ||||||
|  | 	// for user certificates. | ||||||
|  | 	SupportedCriticalOptions []string | ||||||
|  |  | ||||||
|  | 	// IsUserAuthority should return true if the key is recognized as an | ||||||
|  | 	// authority for the given user certificate. This allows for | ||||||
|  | 	// certificates to be signed by other certificates. This must be set | ||||||
|  | 	// if this CertChecker will be checking user certificates. | ||||||
|  | 	IsUserAuthority func(auth PublicKey) bool | ||||||
|  |  | ||||||
|  | 	// IsHostAuthority should report whether the key is recognized as | ||||||
|  | 	// an authority for this host. This allows for certificates to be | ||||||
|  | 	// signed by other keys, and for those other keys to only be valid | ||||||
|  | 	// signers for particular hostnames. This must be set if this | ||||||
|  | 	// CertChecker will be checking host certificates. | ||||||
|  | 	IsHostAuthority func(auth PublicKey, address string) bool | ||||||
|  |  | ||||||
|  | 	// Clock is used for verifying time stamps. If nil, time.Now | ||||||
|  | 	// is used. | ||||||
|  | 	Clock func() time.Time | ||||||
|  |  | ||||||
|  | 	// UserKeyFallback is called when CertChecker.Authenticate encounters a | ||||||
|  | 	// public key that is not a certificate. It must implement validation | ||||||
|  | 	// of user keys or else, if nil, all such keys are rejected. | ||||||
|  | 	UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) | ||||||
|  |  | ||||||
|  | 	// HostKeyFallback is called when CertChecker.CheckHostKey encounters a | ||||||
|  | 	// public key that is not a certificate. It must implement host key | ||||||
|  | 	// validation or else, if nil, all such keys are rejected. | ||||||
|  | 	HostKeyFallback HostKeyCallback | ||||||
|  |  | ||||||
|  | 	// IsRevoked is called for each certificate so that revocation checking | ||||||
|  | 	// can be implemented. It should return true if the given certificate | ||||||
|  | 	// is revoked and false otherwise. If nil, no certificates are | ||||||
|  | 	// considered to have been revoked. | ||||||
|  | 	IsRevoked func(cert *Certificate) bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CheckHostKey checks a host key certificate. This method can be | ||||||
|  | // plugged into ClientConfig.HostKeyCallback. | ||||||
|  | func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error { | ||||||
|  | 	cert, ok := key.(*Certificate) | ||||||
|  | 	if !ok { | ||||||
|  | 		if c.HostKeyFallback != nil { | ||||||
|  | 			return c.HostKeyFallback(addr, remote, key) | ||||||
|  | 		} | ||||||
|  | 		return errors.New("ssh: non-certificate host key") | ||||||
|  | 	} | ||||||
|  | 	if cert.CertType != HostCert { | ||||||
|  | 		return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType) | ||||||
|  | 	} | ||||||
|  | 	if !c.IsHostAuthority(cert.SignatureKey, addr) { | ||||||
|  | 		return fmt.Errorf("ssh: no authorities for hostname: %v", addr) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	hostname, _, err := net.SplitHostPort(addr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Pass hostname only as principal for host certificates (consistent with OpenSSH) | ||||||
|  | 	return c.CheckCert(hostname, cert) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Authenticate checks a user certificate. Authenticate can be used as | ||||||
|  | // a value for ServerConfig.PublicKeyCallback. | ||||||
|  | func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) { | ||||||
|  | 	cert, ok := pubKey.(*Certificate) | ||||||
|  | 	if !ok { | ||||||
|  | 		if c.UserKeyFallback != nil { | ||||||
|  | 			return c.UserKeyFallback(conn, pubKey) | ||||||
|  | 		} | ||||||
|  | 		return nil, errors.New("ssh: normal key pairs not accepted") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if cert.CertType != UserCert { | ||||||
|  | 		return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType) | ||||||
|  | 	} | ||||||
|  | 	if !c.IsUserAuthority(cert.SignatureKey) { | ||||||
|  | 		return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := c.CheckCert(conn.User(), cert); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &cert.Permissions, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and | ||||||
|  | // the signature of the certificate. | ||||||
|  | func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { | ||||||
|  | 	if c.IsRevoked != nil && c.IsRevoked(cert) { | ||||||
|  | 		return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for opt := range cert.CriticalOptions { | ||||||
|  | 		// sourceAddressCriticalOption will be enforced by | ||||||
|  | 		// serverAuthenticate | ||||||
|  | 		if opt == sourceAddressCriticalOption { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		found := false | ||||||
|  | 		for _, supp := range c.SupportedCriticalOptions { | ||||||
|  | 			if supp == opt { | ||||||
|  | 				found = true | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if !found { | ||||||
|  | 			return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(cert.ValidPrincipals) > 0 { | ||||||
|  | 		// By default, certs are valid for all users/hosts. | ||||||
|  | 		found := false | ||||||
|  | 		for _, p := range cert.ValidPrincipals { | ||||||
|  | 			if p == principal { | ||||||
|  | 				found = true | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if !found { | ||||||
|  | 			return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	clock := c.Clock | ||||||
|  | 	if clock == nil { | ||||||
|  | 		clock = time.Now | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	unixNow := clock().Unix() | ||||||
|  | 	if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) { | ||||||
|  | 		return fmt.Errorf("ssh: cert is not yet valid") | ||||||
|  | 	} | ||||||
|  | 	if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) { | ||||||
|  | 		return fmt.Errorf("ssh: cert has expired") | ||||||
|  | 	} | ||||||
|  | 	if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { | ||||||
|  | 		return fmt.Errorf("ssh: certificate signature does not verify") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SignCert sets c.SignatureKey to the authority's public key and stores a | ||||||
|  | // Signature, by authority, in the certificate. | ||||||
|  | func (c *Certificate) SignCert(rand io.Reader, authority Signer) error { | ||||||
|  | 	c.Nonce = make([]byte, 32) | ||||||
|  | 	if _, err := io.ReadFull(rand, c.Nonce); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	c.SignatureKey = authority.PublicKey() | ||||||
|  |  | ||||||
|  | 	sig, err := authority.Sign(rand, c.bytesForSigning()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	c.Signature = sig | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var certAlgoNames = map[string]string{ | ||||||
|  | 	KeyAlgoRSA:      CertAlgoRSAv01, | ||||||
|  | 	KeyAlgoDSA:      CertAlgoDSAv01, | ||||||
|  | 	KeyAlgoECDSA256: CertAlgoECDSA256v01, | ||||||
|  | 	KeyAlgoECDSA384: CertAlgoECDSA384v01, | ||||||
|  | 	KeyAlgoECDSA521: CertAlgoECDSA521v01, | ||||||
|  | 	KeyAlgoED25519:  CertAlgoED25519v01, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // certToPrivAlgo returns the underlying algorithm for a certificate algorithm. | ||||||
|  | // Panics if a non-certificate algorithm is passed. | ||||||
|  | func certToPrivAlgo(algo string) string { | ||||||
|  | 	for privAlgo, pubAlgo := range certAlgoNames { | ||||||
|  | 		if pubAlgo == algo { | ||||||
|  | 			return privAlgo | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	panic("unknown cert algorithm") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (cert *Certificate) bytesForSigning() []byte { | ||||||
|  | 	c2 := *cert | ||||||
|  | 	c2.Signature = nil | ||||||
|  | 	out := c2.Marshal() | ||||||
|  | 	// Drop trailing signature length. | ||||||
|  | 	return out[:len(out)-4] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Marshal serializes c into OpenSSH's wire format. It is part of the | ||||||
|  | // PublicKey interface. | ||||||
|  | func (c *Certificate) Marshal() []byte { | ||||||
|  | 	generic := genericCertData{ | ||||||
|  | 		Serial:          c.Serial, | ||||||
|  | 		CertType:        c.CertType, | ||||||
|  | 		KeyId:           c.KeyId, | ||||||
|  | 		ValidPrincipals: marshalStringList(c.ValidPrincipals), | ||||||
|  | 		ValidAfter:      uint64(c.ValidAfter), | ||||||
|  | 		ValidBefore:     uint64(c.ValidBefore), | ||||||
|  | 		CriticalOptions: marshalTuples(c.CriticalOptions), | ||||||
|  | 		Extensions:      marshalTuples(c.Extensions), | ||||||
|  | 		Reserved:        c.Reserved, | ||||||
|  | 		SignatureKey:    c.SignatureKey.Marshal(), | ||||||
|  | 	} | ||||||
|  | 	if c.Signature != nil { | ||||||
|  | 		generic.Signature = Marshal(c.Signature) | ||||||
|  | 	} | ||||||
|  | 	genericBytes := Marshal(&generic) | ||||||
|  | 	keyBytes := c.Key.Marshal() | ||||||
|  | 	_, keyBytes, _ = parseString(keyBytes) | ||||||
|  | 	prefix := Marshal(&struct { | ||||||
|  | 		Name  string | ||||||
|  | 		Nonce []byte | ||||||
|  | 		Key   []byte `ssh:"rest"` | ||||||
|  | 	}{c.Type(), c.Nonce, keyBytes}) | ||||||
|  |  | ||||||
|  | 	result := make([]byte, 0, len(prefix)+len(genericBytes)) | ||||||
|  | 	result = append(result, prefix...) | ||||||
|  | 	result = append(result, genericBytes...) | ||||||
|  | 	return result | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Type returns the key name. It is part of the PublicKey interface. | ||||||
|  | func (c *Certificate) Type() string { | ||||||
|  | 	algo, ok := certAlgoNames[c.Key.Type()] | ||||||
|  | 	if !ok { | ||||||
|  | 		panic("unknown cert key type " + c.Key.Type()) | ||||||
|  | 	} | ||||||
|  | 	return algo | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Verify verifies a signature against the certificate's public | ||||||
|  | // key. It is part of the PublicKey interface. | ||||||
|  | func (c *Certificate) Verify(data []byte, sig *Signature) error { | ||||||
|  | 	return c.Key.Verify(data, sig) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) { | ||||||
|  | 	format, in, ok := parseString(in) | ||||||
|  | 	if !ok { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	out = &Signature{ | ||||||
|  | 		Format: string(format), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if out.Blob, in, ok = parseString(in); !ok { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return out, in, ok | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) { | ||||||
|  | 	sigBytes, rest, ok := parseString(in) | ||||||
|  | 	if !ok { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	out, trailing, ok := parseSignatureBody(sigBytes) | ||||||
|  | 	if !ok || len(trailing) > 0 { | ||||||
|  | 		return nil, nil, false | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
							
								
								
									
										633
									
								
								vendor/golang.org/x/crypto/ssh/channel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										633
									
								
								vendor/golang.org/x/crypto/ssh/channel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,633 @@ | |||||||
|  | // 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 ( | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"log" | ||||||
|  | 	"sync" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	minPacketLength = 9 | ||||||
|  | 	// channelMaxPacket contains the maximum number of bytes that will be | ||||||
|  | 	// sent in a single packet. As per RFC 4253, section 6.1, 32k is also | ||||||
|  | 	// the minimum. | ||||||
|  | 	channelMaxPacket = 1 << 15 | ||||||
|  | 	// We follow OpenSSH here. | ||||||
|  | 	channelWindowSize = 64 * channelMaxPacket | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // NewChannel represents an incoming request to a channel. It must either be | ||||||
|  | // accepted for use by calling Accept, or rejected by calling Reject. | ||||||
|  | type NewChannel interface { | ||||||
|  | 	// Accept accepts the channel creation request. It returns the Channel | ||||||
|  | 	// and a Go channel containing SSH requests. The Go channel must be | ||||||
|  | 	// serviced otherwise the Channel will hang. | ||||||
|  | 	Accept() (Channel, <-chan *Request, error) | ||||||
|  |  | ||||||
|  | 	// Reject rejects the channel creation request. After calling | ||||||
|  | 	// this, no other methods on the Channel may be called. | ||||||
|  | 	Reject(reason RejectionReason, message string) error | ||||||
|  |  | ||||||
|  | 	// ChannelType returns the type of the channel, as supplied by the | ||||||
|  | 	// client. | ||||||
|  | 	ChannelType() string | ||||||
|  |  | ||||||
|  | 	// ExtraData returns the arbitrary payload for this channel, as supplied | ||||||
|  | 	// by the client. This data is specific to the channel type. | ||||||
|  | 	ExtraData() []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // A Channel is an ordered, reliable, flow-controlled, duplex stream | ||||||
|  | // that is multiplexed over an SSH connection. | ||||||
|  | type Channel interface { | ||||||
|  | 	// Read reads up to len(data) bytes from the channel. | ||||||
|  | 	Read(data []byte) (int, error) | ||||||
|  |  | ||||||
|  | 	// Write writes len(data) bytes to the channel. | ||||||
|  | 	Write(data []byte) (int, error) | ||||||
|  |  | ||||||
|  | 	// Close signals end of channel use. No data may be sent after this | ||||||
|  | 	// call. | ||||||
|  | 	Close() error | ||||||
|  |  | ||||||
|  | 	// CloseWrite signals the end of sending in-band | ||||||
|  | 	// data. Requests may still be sent, and the other side may | ||||||
|  | 	// still send data | ||||||
|  | 	CloseWrite() error | ||||||
|  |  | ||||||
|  | 	// SendRequest sends a channel request.  If wantReply is true, | ||||||
|  | 	// it will wait for a reply and return the result as a | ||||||
|  | 	// boolean, otherwise the return value will be false. Channel | ||||||
|  | 	// requests are out-of-band messages so they may be sent even | ||||||
|  | 	// if the data stream is closed or blocked by flow control. | ||||||
|  | 	// If the channel is closed before a reply is returned, io.EOF | ||||||
|  | 	// is returned. | ||||||
|  | 	SendRequest(name string, wantReply bool, payload []byte) (bool, error) | ||||||
|  |  | ||||||
|  | 	// Stderr returns an io.ReadWriter that writes to this channel | ||||||
|  | 	// with the extended data type set to stderr. Stderr may | ||||||
|  | 	// safely be read and written from a different goroutine than | ||||||
|  | 	// Read and Write respectively. | ||||||
|  | 	Stderr() io.ReadWriter | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Request is a request sent outside of the normal stream of | ||||||
|  | // data. Requests can either be specific to an SSH channel, or they | ||||||
|  | // can be global. | ||||||
|  | type Request struct { | ||||||
|  | 	Type      string | ||||||
|  | 	WantReply bool | ||||||
|  | 	Payload   []byte | ||||||
|  |  | ||||||
|  | 	ch  *channel | ||||||
|  | 	mux *mux | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Reply sends a response to a request. It must be called for all requests | ||||||
|  | // where WantReply is true and is a no-op otherwise. The payload argument is | ||||||
|  | // ignored for replies to channel-specific requests. | ||||||
|  | func (r *Request) Reply(ok bool, payload []byte) error { | ||||||
|  | 	if !r.WantReply { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if r.ch == nil { | ||||||
|  | 		return r.mux.ackRequest(ok, payload) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return r.ch.ackRequest(ok) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RejectionReason is an enumeration used when rejecting channel creation | ||||||
|  | // requests. See RFC 4254, section 5.1. | ||||||
|  | type RejectionReason uint32 | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	Prohibited RejectionReason = iota + 1 | ||||||
|  | 	ConnectionFailed | ||||||
|  | 	UnknownChannelType | ||||||
|  | 	ResourceShortage | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // String converts the rejection reason to human readable form. | ||||||
|  | func (r RejectionReason) String() string { | ||||||
|  | 	switch r { | ||||||
|  | 	case Prohibited: | ||||||
|  | 		return "administratively prohibited" | ||||||
|  | 	case ConnectionFailed: | ||||||
|  | 		return "connect failed" | ||||||
|  | 	case UnknownChannelType: | ||||||
|  | 		return "unknown channel type" | ||||||
|  | 	case ResourceShortage: | ||||||
|  | 		return "resource shortage" | ||||||
|  | 	} | ||||||
|  | 	return fmt.Sprintf("unknown reason %d", int(r)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func min(a uint32, b int) uint32 { | ||||||
|  | 	if a < uint32(b) { | ||||||
|  | 		return a | ||||||
|  | 	} | ||||||
|  | 	return uint32(b) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type channelDirection uint8 | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	channelInbound channelDirection = iota | ||||||
|  | 	channelOutbound | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // channel is an implementation of the Channel interface that works | ||||||
|  | // with the mux class. | ||||||
|  | type channel struct { | ||||||
|  | 	// R/O after creation | ||||||
|  | 	chanType          string | ||||||
|  | 	extraData         []byte | ||||||
|  | 	localId, remoteId uint32 | ||||||
|  |  | ||||||
|  | 	// maxIncomingPayload and maxRemotePayload are the maximum | ||||||
|  | 	// payload sizes of normal and extended data packets for | ||||||
|  | 	// receiving and sending, respectively. The wire packet will | ||||||
|  | 	// be 9 or 13 bytes larger (excluding encryption overhead). | ||||||
|  | 	maxIncomingPayload uint32 | ||||||
|  | 	maxRemotePayload   uint32 | ||||||
|  |  | ||||||
|  | 	mux *mux | ||||||
|  |  | ||||||
|  | 	// decided is set to true if an accept or reject message has been sent | ||||||
|  | 	// (for outbound channels) or received (for inbound channels). | ||||||
|  | 	decided bool | ||||||
|  |  | ||||||
|  | 	// direction contains either channelOutbound, for channels created | ||||||
|  | 	// locally, or channelInbound, for channels created by the peer. | ||||||
|  | 	direction channelDirection | ||||||
|  |  | ||||||
|  | 	// Pending internal channel messages. | ||||||
|  | 	msg chan interface{} | ||||||
|  |  | ||||||
|  | 	// Since requests have no ID, there can be only one request | ||||||
|  | 	// with WantReply=true outstanding.  This lock is held by a | ||||||
|  | 	// goroutine that has such an outgoing request pending. | ||||||
|  | 	sentRequestMu sync.Mutex | ||||||
|  |  | ||||||
|  | 	incomingRequests chan *Request | ||||||
|  |  | ||||||
|  | 	sentEOF bool | ||||||
|  |  | ||||||
|  | 	// thread-safe data | ||||||
|  | 	remoteWin  window | ||||||
|  | 	pending    *buffer | ||||||
|  | 	extPending *buffer | ||||||
|  |  | ||||||
|  | 	// windowMu protects myWindow, the flow-control window. | ||||||
|  | 	windowMu sync.Mutex | ||||||
|  | 	myWindow uint32 | ||||||
|  |  | ||||||
|  | 	// writeMu serializes calls to mux.conn.writePacket() and | ||||||
|  | 	// protects sentClose and packetPool. This mutex must be | ||||||
|  | 	// different from windowMu, as writePacket can block if there | ||||||
|  | 	// is a key exchange pending. | ||||||
|  | 	writeMu   sync.Mutex | ||||||
|  | 	sentClose bool | ||||||
|  |  | ||||||
|  | 	// packetPool has a buffer for each extended channel ID to | ||||||
|  | 	// save allocations during writes. | ||||||
|  | 	packetPool map[uint32][]byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // writePacket sends a packet. If the packet is a channel close, it updates | ||||||
|  | // sentClose. This method takes the lock c.writeMu. | ||||||
|  | func (ch *channel) writePacket(packet []byte) error { | ||||||
|  | 	ch.writeMu.Lock() | ||||||
|  | 	if ch.sentClose { | ||||||
|  | 		ch.writeMu.Unlock() | ||||||
|  | 		return io.EOF | ||||||
|  | 	} | ||||||
|  | 	ch.sentClose = (packet[0] == msgChannelClose) | ||||||
|  | 	err := ch.mux.conn.writePacket(packet) | ||||||
|  | 	ch.writeMu.Unlock() | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) sendMessage(msg interface{}) error { | ||||||
|  | 	if debugMux { | ||||||
|  | 		log.Printf("send(%d): %#v", ch.mux.chanList.offset, msg) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	p := Marshal(msg) | ||||||
|  | 	binary.BigEndian.PutUint32(p[1:], ch.remoteId) | ||||||
|  | 	return ch.writePacket(p) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WriteExtended writes data to a specific extended stream. These streams are | ||||||
|  | // used, for example, for stderr. | ||||||
|  | func (ch *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) { | ||||||
|  | 	if ch.sentEOF { | ||||||
|  | 		return 0, io.EOF | ||||||
|  | 	} | ||||||
|  | 	// 1 byte message type, 4 bytes remoteId, 4 bytes data length | ||||||
|  | 	opCode := byte(msgChannelData) | ||||||
|  | 	headerLength := uint32(9) | ||||||
|  | 	if extendedCode > 0 { | ||||||
|  | 		headerLength += 4 | ||||||
|  | 		opCode = msgChannelExtendedData | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ch.writeMu.Lock() | ||||||
|  | 	packet := ch.packetPool[extendedCode] | ||||||
|  | 	// We don't remove the buffer from packetPool, so | ||||||
|  | 	// WriteExtended calls from different goroutines will be | ||||||
|  | 	// flagged as errors by the race detector. | ||||||
|  | 	ch.writeMu.Unlock() | ||||||
|  |  | ||||||
|  | 	for len(data) > 0 { | ||||||
|  | 		space := min(ch.maxRemotePayload, len(data)) | ||||||
|  | 		if space, err = ch.remoteWin.reserve(space); err != nil { | ||||||
|  | 			return n, err | ||||||
|  | 		} | ||||||
|  | 		if want := headerLength + space; uint32(cap(packet)) < want { | ||||||
|  | 			packet = make([]byte, want) | ||||||
|  | 		} else { | ||||||
|  | 			packet = packet[:want] | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		todo := data[:space] | ||||||
|  |  | ||||||
|  | 		packet[0] = opCode | ||||||
|  | 		binary.BigEndian.PutUint32(packet[1:], ch.remoteId) | ||||||
|  | 		if extendedCode > 0 { | ||||||
|  | 			binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode)) | ||||||
|  | 		} | ||||||
|  | 		binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo))) | ||||||
|  | 		copy(packet[headerLength:], todo) | ||||||
|  | 		if err = ch.writePacket(packet); err != nil { | ||||||
|  | 			return n, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		n += len(todo) | ||||||
|  | 		data = data[len(todo):] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ch.writeMu.Lock() | ||||||
|  | 	ch.packetPool[extendedCode] = packet | ||||||
|  | 	ch.writeMu.Unlock() | ||||||
|  |  | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) handleData(packet []byte) error { | ||||||
|  | 	headerLen := 9 | ||||||
|  | 	isExtendedData := packet[0] == msgChannelExtendedData | ||||||
|  | 	if isExtendedData { | ||||||
|  | 		headerLen = 13 | ||||||
|  | 	} | ||||||
|  | 	if len(packet) < headerLen { | ||||||
|  | 		// malformed data packet | ||||||
|  | 		return parseError(packet[0]) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var extended uint32 | ||||||
|  | 	if isExtendedData { | ||||||
|  | 		extended = binary.BigEndian.Uint32(packet[5:]) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	length := binary.BigEndian.Uint32(packet[headerLen-4 : headerLen]) | ||||||
|  | 	if length == 0 { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	if length > ch.maxIncomingPayload { | ||||||
|  | 		// TODO(hanwen): should send Disconnect? | ||||||
|  | 		return errors.New("ssh: incoming packet exceeds maximum payload size") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	data := packet[headerLen:] | ||||||
|  | 	if length != uint32(len(data)) { | ||||||
|  | 		return errors.New("ssh: wrong packet length") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ch.windowMu.Lock() | ||||||
|  | 	if ch.myWindow < length { | ||||||
|  | 		ch.windowMu.Unlock() | ||||||
|  | 		// TODO(hanwen): should send Disconnect with reason? | ||||||
|  | 		return errors.New("ssh: remote side wrote too much") | ||||||
|  | 	} | ||||||
|  | 	ch.myWindow -= length | ||||||
|  | 	ch.windowMu.Unlock() | ||||||
|  |  | ||||||
|  | 	if extended == 1 { | ||||||
|  | 		ch.extPending.write(data) | ||||||
|  | 	} else if extended > 0 { | ||||||
|  | 		// discard other extended data. | ||||||
|  | 	} else { | ||||||
|  | 		ch.pending.write(data) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *channel) adjustWindow(n uint32) error { | ||||||
|  | 	c.windowMu.Lock() | ||||||
|  | 	// Since myWindow is managed on our side, and can never exceed | ||||||
|  | 	// the initial window setting, we don't worry about overflow. | ||||||
|  | 	c.myWindow += uint32(n) | ||||||
|  | 	c.windowMu.Unlock() | ||||||
|  | 	return c.sendMessage(windowAdjustMsg{ | ||||||
|  | 		AdditionalBytes: uint32(n), | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) { | ||||||
|  | 	switch extended { | ||||||
|  | 	case 1: | ||||||
|  | 		n, err = c.extPending.Read(data) | ||||||
|  | 	case 0: | ||||||
|  | 		n, err = c.pending.Read(data) | ||||||
|  | 	default: | ||||||
|  | 		return 0, fmt.Errorf("ssh: extended code %d unimplemented", extended) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if n > 0 { | ||||||
|  | 		err = c.adjustWindow(uint32(n)) | ||||||
|  | 		// sendWindowAdjust can return io.EOF if the remote | ||||||
|  | 		// peer has closed the connection, however we want to | ||||||
|  | 		// defer forwarding io.EOF to the caller of Read until | ||||||
|  | 		// the buffer has been drained. | ||||||
|  | 		if n > 0 && err == io.EOF { | ||||||
|  | 			err = nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *channel) close() { | ||||||
|  | 	c.pending.eof() | ||||||
|  | 	c.extPending.eof() | ||||||
|  | 	close(c.msg) | ||||||
|  | 	close(c.incomingRequests) | ||||||
|  | 	c.writeMu.Lock() | ||||||
|  | 	// This is not necessary for a normal channel teardown, but if | ||||||
|  | 	// there was another error, it is. | ||||||
|  | 	c.sentClose = true | ||||||
|  | 	c.writeMu.Unlock() | ||||||
|  | 	// Unblock writers. | ||||||
|  | 	c.remoteWin.close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // responseMessageReceived is called when a success or failure message is | ||||||
|  | // received on a channel to check that such a message is reasonable for the | ||||||
|  | // given channel. | ||||||
|  | func (ch *channel) responseMessageReceived() error { | ||||||
|  | 	if ch.direction == channelInbound { | ||||||
|  | 		return errors.New("ssh: channel response message received on inbound channel") | ||||||
|  | 	} | ||||||
|  | 	if ch.decided { | ||||||
|  | 		return errors.New("ssh: duplicate response received for channel") | ||||||
|  | 	} | ||||||
|  | 	ch.decided = true | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) handlePacket(packet []byte) error { | ||||||
|  | 	switch packet[0] { | ||||||
|  | 	case msgChannelData, msgChannelExtendedData: | ||||||
|  | 		return ch.handleData(packet) | ||||||
|  | 	case msgChannelClose: | ||||||
|  | 		ch.sendMessage(channelCloseMsg{PeersID: ch.remoteId}) | ||||||
|  | 		ch.mux.chanList.remove(ch.localId) | ||||||
|  | 		ch.close() | ||||||
|  | 		return nil | ||||||
|  | 	case msgChannelEOF: | ||||||
|  | 		// RFC 4254 is mute on how EOF affects dataExt messages but | ||||||
|  | 		// it is logical to signal EOF at the same time. | ||||||
|  | 		ch.extPending.eof() | ||||||
|  | 		ch.pending.eof() | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	decoded, err := decode(packet) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch msg := decoded.(type) { | ||||||
|  | 	case *channelOpenFailureMsg: | ||||||
|  | 		if err := ch.responseMessageReceived(); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		ch.mux.chanList.remove(msg.PeersID) | ||||||
|  | 		ch.msg <- msg | ||||||
|  | 	case *channelOpenConfirmMsg: | ||||||
|  | 		if err := ch.responseMessageReceived(); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { | ||||||
|  | 			return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize) | ||||||
|  | 		} | ||||||
|  | 		ch.remoteId = msg.MyID | ||||||
|  | 		ch.maxRemotePayload = msg.MaxPacketSize | ||||||
|  | 		ch.remoteWin.add(msg.MyWindow) | ||||||
|  | 		ch.msg <- msg | ||||||
|  | 	case *windowAdjustMsg: | ||||||
|  | 		if !ch.remoteWin.add(msg.AdditionalBytes) { | ||||||
|  | 			return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes) | ||||||
|  | 		} | ||||||
|  | 	case *channelRequestMsg: | ||||||
|  | 		req := Request{ | ||||||
|  | 			Type:      msg.Request, | ||||||
|  | 			WantReply: msg.WantReply, | ||||||
|  | 			Payload:   msg.RequestSpecificData, | ||||||
|  | 			ch:        ch, | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		ch.incomingRequests <- &req | ||||||
|  | 	default: | ||||||
|  | 		ch.msg <- msg | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel { | ||||||
|  | 	ch := &channel{ | ||||||
|  | 		remoteWin:        window{Cond: newCond()}, | ||||||
|  | 		myWindow:         channelWindowSize, | ||||||
|  | 		pending:          newBuffer(), | ||||||
|  | 		extPending:       newBuffer(), | ||||||
|  | 		direction:        direction, | ||||||
|  | 		incomingRequests: make(chan *Request, chanSize), | ||||||
|  | 		msg:              make(chan interface{}, chanSize), | ||||||
|  | 		chanType:         chanType, | ||||||
|  | 		extraData:        extraData, | ||||||
|  | 		mux:              m, | ||||||
|  | 		packetPool:       make(map[uint32][]byte), | ||||||
|  | 	} | ||||||
|  | 	ch.localId = m.chanList.add(ch) | ||||||
|  | 	return ch | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var errUndecided = errors.New("ssh: must Accept or Reject channel") | ||||||
|  | var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once") | ||||||
|  |  | ||||||
|  | type extChannel struct { | ||||||
|  | 	code uint32 | ||||||
|  | 	ch   *channel | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *extChannel) Write(data []byte) (n int, err error) { | ||||||
|  | 	return e.ch.WriteExtended(data, e.code) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *extChannel) Read(data []byte) (n int, err error) { | ||||||
|  | 	return e.ch.ReadExtended(data, e.code) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) Accept() (Channel, <-chan *Request, error) { | ||||||
|  | 	if ch.decided { | ||||||
|  | 		return nil, nil, errDecidedAlready | ||||||
|  | 	} | ||||||
|  | 	ch.maxIncomingPayload = channelMaxPacket | ||||||
|  | 	confirm := channelOpenConfirmMsg{ | ||||||
|  | 		PeersID:       ch.remoteId, | ||||||
|  | 		MyID:          ch.localId, | ||||||
|  | 		MyWindow:      ch.myWindow, | ||||||
|  | 		MaxPacketSize: ch.maxIncomingPayload, | ||||||
|  | 	} | ||||||
|  | 	ch.decided = true | ||||||
|  | 	if err := ch.sendMessage(confirm); err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ch, ch.incomingRequests, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) Reject(reason RejectionReason, message string) error { | ||||||
|  | 	if ch.decided { | ||||||
|  | 		return errDecidedAlready | ||||||
|  | 	} | ||||||
|  | 	reject := channelOpenFailureMsg{ | ||||||
|  | 		PeersID:  ch.remoteId, | ||||||
|  | 		Reason:   reason, | ||||||
|  | 		Message:  message, | ||||||
|  | 		Language: "en", | ||||||
|  | 	} | ||||||
|  | 	ch.decided = true | ||||||
|  | 	return ch.sendMessage(reject) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) Read(data []byte) (int, error) { | ||||||
|  | 	if !ch.decided { | ||||||
|  | 		return 0, errUndecided | ||||||
|  | 	} | ||||||
|  | 	return ch.ReadExtended(data, 0) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) Write(data []byte) (int, error) { | ||||||
|  | 	if !ch.decided { | ||||||
|  | 		return 0, errUndecided | ||||||
|  | 	} | ||||||
|  | 	return ch.WriteExtended(data, 0) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) CloseWrite() error { | ||||||
|  | 	if !ch.decided { | ||||||
|  | 		return errUndecided | ||||||
|  | 	} | ||||||
|  | 	ch.sentEOF = true | ||||||
|  | 	return ch.sendMessage(channelEOFMsg{ | ||||||
|  | 		PeersID: ch.remoteId}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) Close() error { | ||||||
|  | 	if !ch.decided { | ||||||
|  | 		return errUndecided | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ch.sendMessage(channelCloseMsg{ | ||||||
|  | 		PeersID: ch.remoteId}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Extended returns an io.ReadWriter that sends and receives data on the given, | ||||||
|  | // SSH extended stream. Such streams are used, for example, for stderr. | ||||||
|  | func (ch *channel) Extended(code uint32) io.ReadWriter { | ||||||
|  | 	if !ch.decided { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return &extChannel{code, ch} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) Stderr() io.ReadWriter { | ||||||
|  | 	return ch.Extended(1) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { | ||||||
|  | 	if !ch.decided { | ||||||
|  | 		return false, errUndecided | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if wantReply { | ||||||
|  | 		ch.sentRequestMu.Lock() | ||||||
|  | 		defer ch.sentRequestMu.Unlock() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	msg := channelRequestMsg{ | ||||||
|  | 		PeersID:             ch.remoteId, | ||||||
|  | 		Request:             name, | ||||||
|  | 		WantReply:           wantReply, | ||||||
|  | 		RequestSpecificData: payload, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := ch.sendMessage(msg); err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if wantReply { | ||||||
|  | 		m, ok := (<-ch.msg) | ||||||
|  | 		if !ok { | ||||||
|  | 			return false, io.EOF | ||||||
|  | 		} | ||||||
|  | 		switch m.(type) { | ||||||
|  | 		case *channelRequestFailureMsg: | ||||||
|  | 			return false, nil | ||||||
|  | 		case *channelRequestSuccessMsg: | ||||||
|  | 			return true, nil | ||||||
|  | 		default: | ||||||
|  | 			return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", m) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return false, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ackRequest either sends an ack or nack to the channel request. | ||||||
|  | func (ch *channel) ackRequest(ok bool) error { | ||||||
|  | 	if !ch.decided { | ||||||
|  | 		return errUndecided | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var msg interface{} | ||||||
|  | 	if !ok { | ||||||
|  | 		msg = channelRequestFailureMsg{ | ||||||
|  | 			PeersID: ch.remoteId, | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		msg = channelRequestSuccessMsg{ | ||||||
|  | 			PeersID: ch.remoteId, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return ch.sendMessage(msg) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) ChannelType() string { | ||||||
|  | 	return ch.chanType | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ch *channel) ExtraData() []byte { | ||||||
|  | 	return ch.extraData | ||||||
|  | } | ||||||
							
								
								
									
										629
									
								
								vendor/golang.org/x/crypto/ssh/cipher.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										629
									
								
								vendor/golang.org/x/crypto/ssh/cipher.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,629 @@ | |||||||
|  | // 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 ( | ||||||
|  | 	"crypto/aes" | ||||||
|  | 	"crypto/cipher" | ||||||
|  | 	"crypto/des" | ||||||
|  | 	"crypto/rc4" | ||||||
|  | 	"crypto/subtle" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"hash" | ||||||
|  | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher. | ||||||
|  |  | ||||||
|  | 	// RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations | ||||||
|  | 	// MUST be able to process (plus a few more kilobytes for padding and mac). The RFC | ||||||
|  | 	// indicates implementations SHOULD be able to handle larger packet sizes, but then | ||||||
|  | 	// waffles on about reasonable limits. | ||||||
|  | 	// | ||||||
|  | 	// OpenSSH caps their maxPacket at 256kB so we choose to do | ||||||
|  | 	// the same. maxPacket is also used to ensure that uint32 | ||||||
|  | 	// length fields do not overflow, so it should remain well | ||||||
|  | 	// below 4G. | ||||||
|  | 	maxPacket = 256 * 1024 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // noneCipher implements cipher.Stream and provides no encryption. It is used | ||||||
|  | // by the transport before the first key-exchange. | ||||||
|  | type noneCipher struct{} | ||||||
|  |  | ||||||
|  | func (c noneCipher) XORKeyStream(dst, src []byte) { | ||||||
|  | 	copy(dst, src) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newAESCTR(key, iv []byte) (cipher.Stream, error) { | ||||||
|  | 	c, err := aes.NewCipher(key) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return cipher.NewCTR(c, iv), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newRC4(key, iv []byte) (cipher.Stream, error) { | ||||||
|  | 	return rc4.NewCipher(key) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type streamCipherMode struct { | ||||||
|  | 	keySize    int | ||||||
|  | 	ivSize     int | ||||||
|  | 	skip       int | ||||||
|  | 	createFunc func(key, iv []byte) (cipher.Stream, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *streamCipherMode) createStream(key, iv []byte) (cipher.Stream, error) { | ||||||
|  | 	if len(key) < c.keySize { | ||||||
|  | 		panic("ssh: key length too small for cipher") | ||||||
|  | 	} | ||||||
|  | 	if len(iv) < c.ivSize { | ||||||
|  | 		panic("ssh: iv too small for cipher") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	stream, err := c.createFunc(key[:c.keySize], iv[:c.ivSize]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var streamDump []byte | ||||||
|  | 	if c.skip > 0 { | ||||||
|  | 		streamDump = make([]byte, 512) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for remainingToDump := c.skip; remainingToDump > 0; { | ||||||
|  | 		dumpThisTime := remainingToDump | ||||||
|  | 		if dumpThisTime > len(streamDump) { | ||||||
|  | 			dumpThisTime = len(streamDump) | ||||||
|  | 		} | ||||||
|  | 		stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) | ||||||
|  | 		remainingToDump -= dumpThisTime | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return stream, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // cipherModes documents properties of supported ciphers. Ciphers not included | ||||||
|  | // are not supported and will not be negotiated, even if explicitly requested in | ||||||
|  | // ClientConfig.Crypto.Ciphers. | ||||||
|  | var cipherModes = map[string]*streamCipherMode{ | ||||||
|  | 	// Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms | ||||||
|  | 	// are defined in the order specified in the RFC. | ||||||
|  | 	"aes128-ctr": {16, aes.BlockSize, 0, newAESCTR}, | ||||||
|  | 	"aes192-ctr": {24, aes.BlockSize, 0, newAESCTR}, | ||||||
|  | 	"aes256-ctr": {32, aes.BlockSize, 0, newAESCTR}, | ||||||
|  |  | ||||||
|  | 	// Ciphers from RFC4345, which introduces security-improved arcfour ciphers. | ||||||
|  | 	// They are defined in the order specified in the RFC. | ||||||
|  | 	"arcfour128": {16, 0, 1536, newRC4}, | ||||||
|  | 	"arcfour256": {32, 0, 1536, newRC4}, | ||||||
|  |  | ||||||
|  | 	// Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol. | ||||||
|  | 	// Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and | ||||||
|  | 	// RC4) has problems with weak keys, and should be used with caution." | ||||||
|  | 	// RFC4345 introduces improved versions of Arcfour. | ||||||
|  | 	"arcfour": {16, 0, 0, newRC4}, | ||||||
|  |  | ||||||
|  | 	// AES-GCM is not a stream cipher, so it is constructed with a | ||||||
|  | 	// special case. If we add any more non-stream ciphers, we | ||||||
|  | 	// should invest a cleaner way to do this. | ||||||
|  | 	gcmCipherID: {16, 12, 0, nil}, | ||||||
|  |  | ||||||
|  | 	// CBC mode is insecure and so is not included in the default config. | ||||||
|  | 	// (See http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf). If absolutely | ||||||
|  | 	// needed, it's possible to specify a custom Config to enable it. | ||||||
|  | 	// You should expect that an active attacker can recover plaintext if | ||||||
|  | 	// you do. | ||||||
|  | 	aes128cbcID: {16, aes.BlockSize, 0, nil}, | ||||||
|  |  | ||||||
|  | 	// 3des-cbc is insecure and is disabled by default. | ||||||
|  | 	tripledescbcID: {24, des.BlockSize, 0, nil}, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // prefixLen is the length of the packet prefix that contains the packet length | ||||||
|  | // and number of padding bytes. | ||||||
|  | const prefixLen = 5 | ||||||
|  |  | ||||||
|  | // streamPacketCipher is a packetCipher using a stream cipher. | ||||||
|  | type streamPacketCipher struct { | ||||||
|  | 	mac    hash.Hash | ||||||
|  | 	cipher cipher.Stream | ||||||
|  | 	etm    bool | ||||||
|  |  | ||||||
|  | 	// The following members are to avoid per-packet allocations. | ||||||
|  | 	prefix      [prefixLen]byte | ||||||
|  | 	seqNumBytes [4]byte | ||||||
|  | 	padding     [2 * packetSizeMultiple]byte | ||||||
|  | 	packetData  []byte | ||||||
|  | 	macResult   []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // readPacket reads and decrypt a single packet from the reader argument. | ||||||
|  | func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | ||||||
|  | 	if _, err := io.ReadFull(r, s.prefix[:]); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var encryptedPaddingLength [1]byte | ||||||
|  | 	if s.mac != nil && s.etm { | ||||||
|  | 		copy(encryptedPaddingLength[:], s.prefix[4:5]) | ||||||
|  | 		s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) | ||||||
|  | 	} else { | ||||||
|  | 		s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	length := binary.BigEndian.Uint32(s.prefix[0:4]) | ||||||
|  | 	paddingLength := uint32(s.prefix[4]) | ||||||
|  |  | ||||||
|  | 	var macSize uint32 | ||||||
|  | 	if s.mac != nil { | ||||||
|  | 		s.mac.Reset() | ||||||
|  | 		binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) | ||||||
|  | 		s.mac.Write(s.seqNumBytes[:]) | ||||||
|  | 		if s.etm { | ||||||
|  | 			s.mac.Write(s.prefix[:4]) | ||||||
|  | 			s.mac.Write(encryptedPaddingLength[:]) | ||||||
|  | 		} else { | ||||||
|  | 			s.mac.Write(s.prefix[:]) | ||||||
|  | 		} | ||||||
|  | 		macSize = uint32(s.mac.Size()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if length <= paddingLength+1 { | ||||||
|  | 		return nil, errors.New("ssh: invalid packet length, packet too small") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if length > maxPacket { | ||||||
|  | 		return nil, errors.New("ssh: invalid packet length, packet too large") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// the maxPacket check above ensures that length-1+macSize | ||||||
|  | 	// does not overflow. | ||||||
|  | 	if uint32(cap(s.packetData)) < length-1+macSize { | ||||||
|  | 		s.packetData = make([]byte, length-1+macSize) | ||||||
|  | 	} else { | ||||||
|  | 		s.packetData = s.packetData[:length-1+macSize] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if _, err := io.ReadFull(r, s.packetData); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	mac := s.packetData[length-1:] | ||||||
|  | 	data := s.packetData[:length-1] | ||||||
|  |  | ||||||
|  | 	if s.mac != nil && s.etm { | ||||||
|  | 		s.mac.Write(data) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	s.cipher.XORKeyStream(data, data) | ||||||
|  |  | ||||||
|  | 	if s.mac != nil { | ||||||
|  | 		if !s.etm { | ||||||
|  | 			s.mac.Write(data) | ||||||
|  | 		} | ||||||
|  | 		s.macResult = s.mac.Sum(s.macResult[:0]) | ||||||
|  | 		if subtle.ConstantTimeCompare(s.macResult, mac) != 1 { | ||||||
|  | 			return nil, errors.New("ssh: MAC failure") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return s.packetData[:length-paddingLength-1], nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // writePacket encrypts and sends a packet of data to the writer argument | ||||||
|  | func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | ||||||
|  | 	if len(packet) > maxPacket { | ||||||
|  | 		return errors.New("ssh: packet too large") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	aadlen := 0 | ||||||
|  | 	if s.mac != nil && s.etm { | ||||||
|  | 		// packet length is not encrypted for EtM modes | ||||||
|  | 		aadlen = 4 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple | ||||||
|  | 	if paddingLength < 4 { | ||||||
|  | 		paddingLength += packetSizeMultiple | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	length := len(packet) + 1 + paddingLength | ||||||
|  | 	binary.BigEndian.PutUint32(s.prefix[:], uint32(length)) | ||||||
|  | 	s.prefix[4] = byte(paddingLength) | ||||||
|  | 	padding := s.padding[:paddingLength] | ||||||
|  | 	if _, err := io.ReadFull(rand, padding); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if s.mac != nil { | ||||||
|  | 		s.mac.Reset() | ||||||
|  | 		binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) | ||||||
|  | 		s.mac.Write(s.seqNumBytes[:]) | ||||||
|  |  | ||||||
|  | 		if s.etm { | ||||||
|  | 			// For EtM algorithms, the packet length must stay unencrypted, | ||||||
|  | 			// but the following data (padding length) must be encrypted | ||||||
|  | 			s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		s.mac.Write(s.prefix[:]) | ||||||
|  |  | ||||||
|  | 		if !s.etm { | ||||||
|  | 			// For non-EtM algorithms, the algorithm is applied on unencrypted data | ||||||
|  | 			s.mac.Write(packet) | ||||||
|  | 			s.mac.Write(padding) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !(s.mac != nil && s.etm) { | ||||||
|  | 		// For EtM algorithms, the padding length has already been encrypted | ||||||
|  | 		// and the packet length must remain unencrypted | ||||||
|  | 		s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	s.cipher.XORKeyStream(packet, packet) | ||||||
|  | 	s.cipher.XORKeyStream(padding, padding) | ||||||
|  |  | ||||||
|  | 	if s.mac != nil && s.etm { | ||||||
|  | 		// For EtM algorithms, packet and padding must be encrypted | ||||||
|  | 		s.mac.Write(packet) | ||||||
|  | 		s.mac.Write(padding) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if _, err := w.Write(s.prefix[:]); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if _, err := w.Write(packet); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if _, err := w.Write(padding); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if s.mac != nil { | ||||||
|  | 		s.macResult = s.mac.Sum(s.macResult[:0]) | ||||||
|  | 		if _, err := w.Write(s.macResult); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type gcmCipher struct { | ||||||
|  | 	aead   cipher.AEAD | ||||||
|  | 	prefix [4]byte | ||||||
|  | 	iv     []byte | ||||||
|  | 	buf    []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newGCMCipher(iv, key []byte) (packetCipher, error) { | ||||||
|  | 	c, err := aes.NewCipher(key) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	aead, err := cipher.NewGCM(c) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &gcmCipher{ | ||||||
|  | 		aead: aead, | ||||||
|  | 		iv:   iv, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const gcmTagSize = 16 | ||||||
|  |  | ||||||
|  | func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | ||||||
|  | 	// Pad out to multiple of 16 bytes. This is different from the | ||||||
|  | 	// stream cipher because that encrypts the length too. | ||||||
|  | 	padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) | ||||||
|  | 	if padding < 4 { | ||||||
|  | 		padding += packetSizeMultiple | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	length := uint32(len(packet) + int(padding) + 1) | ||||||
|  | 	binary.BigEndian.PutUint32(c.prefix[:], length) | ||||||
|  | 	if _, err := w.Write(c.prefix[:]); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if cap(c.buf) < int(length) { | ||||||
|  | 		c.buf = make([]byte, length) | ||||||
|  | 	} else { | ||||||
|  | 		c.buf = c.buf[:length] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c.buf[0] = padding | ||||||
|  | 	copy(c.buf[1:], packet) | ||||||
|  | 	if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:]) | ||||||
|  | 	if _, err := w.Write(c.buf); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	c.incIV() | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *gcmCipher) incIV() { | ||||||
|  | 	for i := 4 + 7; i >= 4; i-- { | ||||||
|  | 		c.iv[i]++ | ||||||
|  | 		if c.iv[i] != 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | ||||||
|  | 	if _, err := io.ReadFull(r, c.prefix[:]); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	length := binary.BigEndian.Uint32(c.prefix[:]) | ||||||
|  | 	if length > maxPacket { | ||||||
|  | 		return nil, errors.New("ssh: max packet length exceeded") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if cap(c.buf) < int(length+gcmTagSize) { | ||||||
|  | 		c.buf = make([]byte, length+gcmTagSize) | ||||||
|  | 	} else { | ||||||
|  | 		c.buf = c.buf[:length+gcmTagSize] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if _, err := io.ReadFull(r, c.buf); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	c.incIV() | ||||||
|  |  | ||||||
|  | 	padding := plain[0] | ||||||
|  | 	if padding < 4 { | ||||||
|  | 		// padding is a byte, so it automatically satisfies | ||||||
|  | 		// the maximum size, which is 255. | ||||||
|  | 		return nil, fmt.Errorf("ssh: illegal padding %d", padding) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if int(padding+1) >= len(plain) { | ||||||
|  | 		return nil, fmt.Errorf("ssh: padding %d too large", padding) | ||||||
|  | 	} | ||||||
|  | 	plain = plain[1 : length-uint32(padding)] | ||||||
|  | 	return plain, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1 | ||||||
|  | type cbcCipher struct { | ||||||
|  | 	mac       hash.Hash | ||||||
|  | 	macSize   uint32 | ||||||
|  | 	decrypter cipher.BlockMode | ||||||
|  | 	encrypter cipher.BlockMode | ||||||
|  |  | ||||||
|  | 	// The following members are to avoid per-packet allocations. | ||||||
|  | 	seqNumBytes [4]byte | ||||||
|  | 	packetData  []byte | ||||||
|  | 	macResult   []byte | ||||||
|  |  | ||||||
|  | 	// Amount of data we should still read to hide which | ||||||
|  | 	// verification error triggered. | ||||||
|  | 	oracleCamouflage uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newCBCCipher(c cipher.Block, iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { | ||||||
|  | 	cbc := &cbcCipher{ | ||||||
|  | 		mac:        macModes[algs.MAC].new(macKey), | ||||||
|  | 		decrypter:  cipher.NewCBCDecrypter(c, iv), | ||||||
|  | 		encrypter:  cipher.NewCBCEncrypter(c, iv), | ||||||
|  | 		packetData: make([]byte, 1024), | ||||||
|  | 	} | ||||||
|  | 	if cbc.mac != nil { | ||||||
|  | 		cbc.macSize = uint32(cbc.mac.Size()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return cbc, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { | ||||||
|  | 	c, err := aes.NewCipher(key) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	cbc, err := newCBCCipher(c, iv, key, macKey, algs) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return cbc, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newTripleDESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { | ||||||
|  | 	c, err := des.NewTripleDESCipher(key) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	cbc, err := newCBCCipher(c, iv, key, macKey, algs) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return cbc, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func maxUInt32(a, b int) uint32 { | ||||||
|  | 	if a > b { | ||||||
|  | 		return uint32(a) | ||||||
|  | 	} | ||||||
|  | 	return uint32(b) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	cbcMinPacketSizeMultiple = 8 | ||||||
|  | 	cbcMinPacketSize         = 16 | ||||||
|  | 	cbcMinPaddingSize        = 4 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // cbcError represents a verification error that may leak information. | ||||||
|  | type cbcError string | ||||||
|  |  | ||||||
|  | func (e cbcError) Error() string { return string(e) } | ||||||
|  |  | ||||||
|  | func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | ||||||
|  | 	p, err := c.readPacketLeaky(seqNum, r) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if _, ok := err.(cbcError); ok { | ||||||
|  | 			// Verification error: read a fixed amount of | ||||||
|  | 			// data, to make distinguishing between | ||||||
|  | 			// failing MAC and failing length check more | ||||||
|  | 			// difficult. | ||||||
|  | 			io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return p, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { | ||||||
|  | 	blockSize := c.decrypter.BlockSize() | ||||||
|  |  | ||||||
|  | 	// Read the header, which will include some of the subsequent data in the | ||||||
|  | 	// case of block ciphers - this is copied back to the payload later. | ||||||
|  | 	// How many bytes of payload/padding will be read with this first read. | ||||||
|  | 	firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize) | ||||||
|  | 	firstBlock := c.packetData[:firstBlockLength] | ||||||
|  | 	if _, err := io.ReadFull(r, firstBlock); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength | ||||||
|  |  | ||||||
|  | 	c.decrypter.CryptBlocks(firstBlock, firstBlock) | ||||||
|  | 	length := binary.BigEndian.Uint32(firstBlock[:4]) | ||||||
|  | 	if length > maxPacket { | ||||||
|  | 		return nil, cbcError("ssh: packet too large") | ||||||
|  | 	} | ||||||
|  | 	if length+4 < maxUInt32(cbcMinPacketSize, blockSize) { | ||||||
|  | 		// The minimum size of a packet is 16 (or the cipher block size, whichever | ||||||
|  | 		// is larger) bytes. | ||||||
|  | 		return nil, cbcError("ssh: packet too small") | ||||||
|  | 	} | ||||||
|  | 	// The length of the packet (including the length field but not the MAC) must | ||||||
|  | 	// be a multiple of the block size or 8, whichever is larger. | ||||||
|  | 	if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 { | ||||||
|  | 		return nil, cbcError("ssh: invalid packet length multiple") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	paddingLength := uint32(firstBlock[4]) | ||||||
|  | 	if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 { | ||||||
|  | 		return nil, cbcError("ssh: invalid packet length") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Positions within the c.packetData buffer: | ||||||
|  | 	macStart := 4 + length | ||||||
|  | 	paddingStart := macStart - paddingLength | ||||||
|  |  | ||||||
|  | 	// Entire packet size, starting before length, ending at end of mac. | ||||||
|  | 	entirePacketSize := macStart + c.macSize | ||||||
|  |  | ||||||
|  | 	// Ensure c.packetData is large enough for the entire packet data. | ||||||
|  | 	if uint32(cap(c.packetData)) < entirePacketSize { | ||||||
|  | 		// Still need to upsize and copy, but this should be rare at runtime, only | ||||||
|  | 		// on upsizing the packetData buffer. | ||||||
|  | 		c.packetData = make([]byte, entirePacketSize) | ||||||
|  | 		copy(c.packetData, firstBlock) | ||||||
|  | 	} else { | ||||||
|  | 		c.packetData = c.packetData[:entirePacketSize] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	n, err := io.ReadFull(r, c.packetData[firstBlockLength:]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	c.oracleCamouflage -= uint32(n) | ||||||
|  |  | ||||||
|  | 	remainingCrypted := c.packetData[firstBlockLength:macStart] | ||||||
|  | 	c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted) | ||||||
|  |  | ||||||
|  | 	mac := c.packetData[macStart:] | ||||||
|  | 	if c.mac != nil { | ||||||
|  | 		c.mac.Reset() | ||||||
|  | 		binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) | ||||||
|  | 		c.mac.Write(c.seqNumBytes[:]) | ||||||
|  | 		c.mac.Write(c.packetData[:macStart]) | ||||||
|  | 		c.macResult = c.mac.Sum(c.macResult[:0]) | ||||||
|  | 		if subtle.ConstantTimeCompare(c.macResult, mac) != 1 { | ||||||
|  | 			return nil, cbcError("ssh: MAC failure") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return c.packetData[prefixLen:paddingStart], nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | ||||||
|  | 	effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize()) | ||||||
|  |  | ||||||
|  | 	// Length of encrypted portion of the packet (header, payload, padding). | ||||||
|  | 	// Enforce minimum padding and packet size. | ||||||
|  | 	encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize) | ||||||
|  | 	// Enforce block size. | ||||||
|  | 	encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize | ||||||
|  |  | ||||||
|  | 	length := encLength - 4 | ||||||
|  | 	paddingLength := int(length) - (1 + len(packet)) | ||||||
|  |  | ||||||
|  | 	// Overall buffer contains: header, payload, padding, mac. | ||||||
|  | 	// Space for the MAC is reserved in the capacity but not the slice length. | ||||||
|  | 	bufferSize := encLength + c.macSize | ||||||
|  | 	if uint32(cap(c.packetData)) < bufferSize { | ||||||
|  | 		c.packetData = make([]byte, encLength, bufferSize) | ||||||
|  | 	} else { | ||||||
|  | 		c.packetData = c.packetData[:encLength] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	p := c.packetData | ||||||
|  |  | ||||||
|  | 	// Packet header. | ||||||
|  | 	binary.BigEndian.PutUint32(p, length) | ||||||
|  | 	p = p[4:] | ||||||
|  | 	p[0] = byte(paddingLength) | ||||||
|  |  | ||||||
|  | 	// Payload. | ||||||
|  | 	p = p[1:] | ||||||
|  | 	copy(p, packet) | ||||||
|  |  | ||||||
|  | 	// Padding. | ||||||
|  | 	p = p[len(packet):] | ||||||
|  | 	if _, err := io.ReadFull(rand, p); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if c.mac != nil { | ||||||
|  | 		c.mac.Reset() | ||||||
|  | 		binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) | ||||||
|  | 		c.mac.Write(c.seqNumBytes[:]) | ||||||
|  | 		c.mac.Write(c.packetData) | ||||||
|  | 		// The MAC is now appended into the capacity reserved for it earlier. | ||||||
|  | 		c.packetData = c.mac.Sum(c.packetData) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength]) | ||||||
|  |  | ||||||
|  | 	if _, err := w.Write(c.packetData); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										278
									
								
								vendor/golang.org/x/crypto/ssh/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								vendor/golang.org/x/crypto/ssh/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,278 @@ | |||||||
|  | // 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" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"net" | ||||||
|  | 	"os" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Client implements a traditional SSH client that supports shells, | ||||||
|  | // subprocesses, TCP port/streamlocal forwarding and tunneled dialing. | ||||||
|  | type Client struct { | ||||||
|  | 	Conn | ||||||
|  |  | ||||||
|  | 	forwards        forwardList // forwarded tcpip connections from the remote side | ||||||
|  | 	mu              sync.Mutex | ||||||
|  | 	channelHandlers map[string]chan NewChannel | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // HandleChannelOpen returns a channel on which NewChannel requests | ||||||
|  | // for the given type are sent. If the type already is being handled, | ||||||
|  | // nil is returned. The channel is closed when the connection is closed. | ||||||
|  | func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel { | ||||||
|  | 	c.mu.Lock() | ||||||
|  | 	defer c.mu.Unlock() | ||||||
|  | 	if c.channelHandlers == nil { | ||||||
|  | 		// The SSH channel has been closed. | ||||||
|  | 		c := make(chan NewChannel) | ||||||
|  | 		close(c) | ||||||
|  | 		return c | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ch := c.channelHandlers[channelType] | ||||||
|  | 	if ch != nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ch = make(chan NewChannel, chanSize) | ||||||
|  | 	c.channelHandlers[channelType] = ch | ||||||
|  | 	return ch | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewClient creates a Client on top of the given connection. | ||||||
|  | func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client { | ||||||
|  | 	conn := &Client{ | ||||||
|  | 		Conn:            c, | ||||||
|  | 		channelHandlers: make(map[string]chan NewChannel, 1), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	go conn.handleGlobalRequests(reqs) | ||||||
|  | 	go conn.handleChannelOpens(chans) | ||||||
|  | 	go func() { | ||||||
|  | 		conn.Wait() | ||||||
|  | 		conn.forwards.closeAll() | ||||||
|  | 	}() | ||||||
|  | 	go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip")) | ||||||
|  | 	go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-streamlocal@openssh.com")) | ||||||
|  | 	return conn | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewClientConn establishes an authenticated SSH connection using c | ||||||
|  | // as the underlying transport.  The Request and NewChannel channels | ||||||
|  | // must be serviced or the connection will hang. | ||||||
|  | func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) { | ||||||
|  | 	fullConf := *config | ||||||
|  | 	fullConf.SetDefaults() | ||||||
|  | 	if fullConf.HostKeyCallback == nil { | ||||||
|  | 		c.Close() | ||||||
|  | 		return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	conn := &connection{ | ||||||
|  | 		sshConn: sshConn{conn: c}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := conn.clientHandshake(addr, &fullConf); err != nil { | ||||||
|  | 		c.Close() | ||||||
|  | 		return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err) | ||||||
|  | 	} | ||||||
|  | 	conn.mux = newMux(conn.transport) | ||||||
|  | 	return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // clientHandshake performs the client side key exchange. See RFC 4253 Section | ||||||
|  | // 7. | ||||||
|  | func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error { | ||||||
|  | 	if config.ClientVersion != "" { | ||||||
|  | 		c.clientVersion = []byte(config.ClientVersion) | ||||||
|  | 	} else { | ||||||
|  | 		c.clientVersion = []byte(packageVersion) | ||||||
|  | 	} | ||||||
|  | 	var err error | ||||||
|  | 	c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c.transport = newClientTransport( | ||||||
|  | 		newTransport(c.sshConn.conn, config.Rand, true /* is client */), | ||||||
|  | 		c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr()) | ||||||
|  | 	if err := c.transport.waitSession(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c.sessionID = c.transport.getSessionID() | ||||||
|  | 	return c.clientAuthenticate(config) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // verifyHostKeySignature verifies the host key obtained in the key | ||||||
|  | // exchange. | ||||||
|  | func verifyHostKeySignature(hostKey PublicKey, result *kexResult) error { | ||||||
|  | 	sig, rest, ok := parseSignatureBody(result.Signature) | ||||||
|  | 	if len(rest) > 0 || !ok { | ||||||
|  | 		return errors.New("ssh: signature parse error") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return hostKey.Verify(result.H, sig) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewSession opens a new Session for this client. (A session is a remote | ||||||
|  | // execution of a program.) | ||||||
|  | func (c *Client) NewSession() (*Session, error) { | ||||||
|  | 	ch, in, err := c.OpenChannel("session", nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return newSession(ch, in) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *Client) handleGlobalRequests(incoming <-chan *Request) { | ||||||
|  | 	for r := range incoming { | ||||||
|  | 		// This handles keepalive messages and matches | ||||||
|  | 		// the behaviour of OpenSSH. | ||||||
|  | 		r.Reply(false, nil) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // handleChannelOpens channel open messages from the remote side. | ||||||
|  | func (c *Client) handleChannelOpens(in <-chan NewChannel) { | ||||||
|  | 	for ch := range in { | ||||||
|  | 		c.mu.Lock() | ||||||
|  | 		handler := c.channelHandlers[ch.ChannelType()] | ||||||
|  | 		c.mu.Unlock() | ||||||
|  |  | ||||||
|  | 		if handler != nil { | ||||||
|  | 			handler <- ch | ||||||
|  | 		} else { | ||||||
|  | 			ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType())) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c.mu.Lock() | ||||||
|  | 	for _, ch := range c.channelHandlers { | ||||||
|  | 		close(ch) | ||||||
|  | 	} | ||||||
|  | 	c.channelHandlers = nil | ||||||
|  | 	c.mu.Unlock() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Dial starts a client connection to the given SSH server. It is a | ||||||
|  | // convenience function that connects to the given network address, | ||||||
|  | // initiates the SSH handshake, and then sets up a Client.  For access | ||||||
|  | // to incoming channels and requests, use net.Dial with NewClientConn | ||||||
|  | // instead. | ||||||
|  | func Dial(network, addr string, config *ClientConfig) (*Client, error) { | ||||||
|  | 	conn, err := net.DialTimeout(network, addr, config.Timeout) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	c, chans, reqs, err := NewClientConn(conn, addr, config) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return NewClient(c, chans, reqs), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // HostKeyCallback is the function type used for verifying server | ||||||
|  | // keys.  A HostKeyCallback must return nil if the host key is OK, or | ||||||
|  | // an error to reject it. It receives the hostname as passed to Dial | ||||||
|  | // or NewClientConn. The remote address is the RemoteAddr of the | ||||||
|  | // net.Conn underlying the the SSH connection. | ||||||
|  | type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error | ||||||
|  |  | ||||||
|  | // BannerCallback is the function type used for treat the banner sent by | ||||||
|  | // the server. A BannerCallback receives the message sent by the remote server. | ||||||
|  | type BannerCallback func(message string) error | ||||||
|  |  | ||||||
|  | // A ClientConfig structure is used to configure a Client. It must not be | ||||||
|  | // modified after having been passed to an SSH function. | ||||||
|  | type ClientConfig struct { | ||||||
|  | 	// Config contains configuration that is shared between clients and | ||||||
|  | 	// servers. | ||||||
|  | 	Config | ||||||
|  |  | ||||||
|  | 	// User contains the username to authenticate as. | ||||||
|  | 	User string | ||||||
|  |  | ||||||
|  | 	// Auth contains possible authentication methods to use with the | ||||||
|  | 	// server. Only the first instance of a particular RFC 4252 method will | ||||||
|  | 	// be used during authentication. | ||||||
|  | 	Auth []AuthMethod | ||||||
|  |  | ||||||
|  | 	// HostKeyCallback is called during the cryptographic | ||||||
|  | 	// handshake to validate the server's host key. The client | ||||||
|  | 	// configuration must supply this callback for the connection | ||||||
|  | 	// to succeed. The functions InsecureIgnoreHostKey or | ||||||
|  | 	// FixedHostKey can be used for simplistic host key checks. | ||||||
|  | 	HostKeyCallback HostKeyCallback | ||||||
|  |  | ||||||
|  | 	// BannerCallback is called during the SSH dance to display a custom | ||||||
|  | 	// server's message. The client configuration can supply this callback to | ||||||
|  | 	// handle it as wished. The function BannerDisplayStderr can be used for | ||||||
|  | 	// simplistic display on Stderr. | ||||||
|  | 	BannerCallback BannerCallback | ||||||
|  |  | ||||||
|  | 	// ClientVersion contains the version identification string that will | ||||||
|  | 	// be used for the connection. If empty, a reasonable default is used. | ||||||
|  | 	ClientVersion string | ||||||
|  |  | ||||||
|  | 	// HostKeyAlgorithms lists the key types that the client will | ||||||
|  | 	// accept from the server as host key, in order of | ||||||
|  | 	// preference. If empty, a reasonable default is used. Any | ||||||
|  | 	// string returned from PublicKey.Type method may be used, or | ||||||
|  | 	// any of the CertAlgoXxxx and KeyAlgoXxxx constants. | ||||||
|  | 	HostKeyAlgorithms []string | ||||||
|  |  | ||||||
|  | 	// Timeout is the maximum amount of time for the TCP connection to establish. | ||||||
|  | 	// | ||||||
|  | 	// A Timeout of zero means no timeout. | ||||||
|  | 	Timeout time.Duration | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // InsecureIgnoreHostKey returns a function that can be used for | ||||||
|  | // ClientConfig.HostKeyCallback to accept any host key. It should | ||||||
|  | // not be used for production code. | ||||||
|  | func InsecureIgnoreHostKey() HostKeyCallback { | ||||||
|  | 	return func(hostname string, remote net.Addr, key PublicKey) error { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type fixedHostKey struct { | ||||||
|  | 	key PublicKey | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *fixedHostKey) check(hostname string, remote net.Addr, key PublicKey) error { | ||||||
|  | 	if f.key == nil { | ||||||
|  | 		return fmt.Errorf("ssh: required host key was nil") | ||||||
|  | 	} | ||||||
|  | 	if !bytes.Equal(key.Marshal(), f.key.Marshal()) { | ||||||
|  | 		return fmt.Errorf("ssh: host key mismatch") | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // FixedHostKey returns a function for use in | ||||||
|  | // ClientConfig.HostKeyCallback to accept only a specific host key. | ||||||
|  | func FixedHostKey(key PublicKey) HostKeyCallback { | ||||||
|  | 	hk := &fixedHostKey{key} | ||||||
|  | 	return hk.check | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // BannerDisplayStderr returns a function that can be used for | ||||||
|  | // ClientConfig.BannerCallback to display banners on os.Stderr. | ||||||
|  | func BannerDisplayStderr() BannerCallback { | ||||||
|  | 	return func(banner string) error { | ||||||
|  | 		_, err := os.Stderr.WriteString(banner) | ||||||
|  |  | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										510
									
								
								vendor/golang.org/x/crypto/ssh/client_auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								vendor/golang.org/x/crypto/ssh/client_auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,510 @@ | |||||||
|  | // 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" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // clientAuthenticate authenticates with the remote server. See RFC 4252. | ||||||
|  | func (c *connection) clientAuthenticate(config *ClientConfig) error { | ||||||
|  | 	// initiate user auth session | ||||||
|  | 	if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	packet, err := c.transport.readPacket() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	var serviceAccept serviceAcceptMsg | ||||||
|  | 	if err := Unmarshal(packet, &serviceAccept); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// during the authentication phase the client first attempts the "none" method | ||||||
|  | 	// then any untried methods suggested by the server. | ||||||
|  | 	tried := make(map[string]bool) | ||||||
|  | 	var lastMethods []string | ||||||
|  |  | ||||||
|  | 	sessionID := c.transport.getSessionID() | ||||||
|  | 	for auth := AuthMethod(new(noneAuth)); auth != nil; { | ||||||
|  | 		ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if ok { | ||||||
|  | 			// success | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		tried[auth.method()] = true | ||||||
|  | 		if methods == nil { | ||||||
|  | 			methods = lastMethods | ||||||
|  | 		} | ||||||
|  | 		lastMethods = methods | ||||||
|  |  | ||||||
|  | 		auth = nil | ||||||
|  |  | ||||||
|  | 	findNext: | ||||||
|  | 		for _, a := range config.Auth { | ||||||
|  | 			candidateMethod := a.method() | ||||||
|  | 			if tried[candidateMethod] { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			for _, meth := range methods { | ||||||
|  | 				if meth == candidateMethod { | ||||||
|  | 					auth = a | ||||||
|  | 					break findNext | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", keys(tried)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func keys(m map[string]bool) []string { | ||||||
|  | 	s := make([]string, 0, len(m)) | ||||||
|  |  | ||||||
|  | 	for key := range m { | ||||||
|  | 		s = append(s, key) | ||||||
|  | 	} | ||||||
|  | 	return s | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // An AuthMethod represents an instance of an RFC 4252 authentication method. | ||||||
|  | type AuthMethod interface { | ||||||
|  | 	// auth authenticates user over transport t. | ||||||
|  | 	// Returns true if authentication is successful. | ||||||
|  | 	// If authentication is not successful, a []string of alternative | ||||||
|  | 	// method names is returned. If the slice is nil, it will be ignored | ||||||
|  | 	// and the previous set of possible methods will be reused. | ||||||
|  | 	auth(session []byte, user string, p packetConn, rand io.Reader) (bool, []string, error) | ||||||
|  |  | ||||||
|  | 	// method returns the RFC 4252 method name. | ||||||
|  | 	method() string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // "none" authentication, RFC 4252 section 5.2. | ||||||
|  | type noneAuth int | ||||||
|  |  | ||||||
|  | func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { | ||||||
|  | 	if err := c.writePacket(Marshal(&userAuthRequestMsg{ | ||||||
|  | 		User:    user, | ||||||
|  | 		Service: serviceSSH, | ||||||
|  | 		Method:  "none", | ||||||
|  | 	})); err != nil { | ||||||
|  | 		return false, nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return handleAuthResponse(c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (n *noneAuth) method() string { | ||||||
|  | 	return "none" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // passwordCallback is an AuthMethod that fetches the password through | ||||||
|  | // a function call, e.g. by prompting the user. | ||||||
|  | type passwordCallback func() (password string, err error) | ||||||
|  |  | ||||||
|  | func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { | ||||||
|  | 	type passwordAuthMsg struct { | ||||||
|  | 		User     string `sshtype:"50"` | ||||||
|  | 		Service  string | ||||||
|  | 		Method   string | ||||||
|  | 		Reply    bool | ||||||
|  | 		Password string | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pw, err := cb() | ||||||
|  | 	// REVIEW NOTE: is there a need to support skipping a password attempt? | ||||||
|  | 	// The program may only find out that the user doesn't have a password | ||||||
|  | 	// when prompting. | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := c.writePacket(Marshal(&passwordAuthMsg{ | ||||||
|  | 		User:     user, | ||||||
|  | 		Service:  serviceSSH, | ||||||
|  | 		Method:   cb.method(), | ||||||
|  | 		Reply:    false, | ||||||
|  | 		Password: pw, | ||||||
|  | 	})); err != nil { | ||||||
|  | 		return false, nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return handleAuthResponse(c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (cb passwordCallback) method() string { | ||||||
|  | 	return "password" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Password returns an AuthMethod using the given password. | ||||||
|  | func Password(secret string) AuthMethod { | ||||||
|  | 	return passwordCallback(func() (string, error) { return secret, nil }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PasswordCallback returns an AuthMethod that uses a callback for | ||||||
|  | // fetching a password. | ||||||
|  | func PasswordCallback(prompt func() (secret string, err error)) AuthMethod { | ||||||
|  | 	return passwordCallback(prompt) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type publickeyAuthMsg struct { | ||||||
|  | 	User    string `sshtype:"50"` | ||||||
|  | 	Service string | ||||||
|  | 	Method  string | ||||||
|  | 	// HasSig indicates to the receiver packet that the auth request is signed and | ||||||
|  | 	// should be used for authentication of the request. | ||||||
|  | 	HasSig   bool | ||||||
|  | 	Algoname string | ||||||
|  | 	PubKey   []byte | ||||||
|  | 	// Sig is tagged with "rest" so Marshal will exclude it during | ||||||
|  | 	// validateKey | ||||||
|  | 	Sig []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // publicKeyCallback is an AuthMethod that uses a set of key | ||||||
|  | // pairs for authentication. | ||||||
|  | type publicKeyCallback func() ([]Signer, error) | ||||||
|  |  | ||||||
|  | func (cb publicKeyCallback) method() string { | ||||||
|  | 	return "publickey" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { | ||||||
|  | 	// Authentication is performed by sending an enquiry to test if a key is | ||||||
|  | 	// acceptable to the remote. If the key is acceptable, the client will | ||||||
|  | 	// attempt to authenticate with the valid key.  If not the client will repeat | ||||||
|  | 	// the process with the remaining keys. | ||||||
|  |  | ||||||
|  | 	signers, err := cb() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, nil, err | ||||||
|  | 	} | ||||||
|  | 	var methods []string | ||||||
|  | 	for _, signer := range signers { | ||||||
|  | 		ok, err := validateKey(signer.PublicKey(), user, c) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  | 		if !ok { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		pub := signer.PublicKey() | ||||||
|  | 		pubKey := pub.Marshal() | ||||||
|  | 		sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{ | ||||||
|  | 			User:    user, | ||||||
|  | 			Service: serviceSSH, | ||||||
|  | 			Method:  cb.method(), | ||||||
|  | 		}, []byte(pub.Type()), pubKey)) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// manually wrap the serialized signature in a string | ||||||
|  | 		s := Marshal(sign) | ||||||
|  | 		sig := make([]byte, stringLength(len(s))) | ||||||
|  | 		marshalString(sig, s) | ||||||
|  | 		msg := publickeyAuthMsg{ | ||||||
|  | 			User:     user, | ||||||
|  | 			Service:  serviceSSH, | ||||||
|  | 			Method:   cb.method(), | ||||||
|  | 			HasSig:   true, | ||||||
|  | 			Algoname: pub.Type(), | ||||||
|  | 			PubKey:   pubKey, | ||||||
|  | 			Sig:      sig, | ||||||
|  | 		} | ||||||
|  | 		p := Marshal(&msg) | ||||||
|  | 		if err := c.writePacket(p); err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  | 		var success bool | ||||||
|  | 		success, methods, err = handleAuthResponse(c) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// If authentication succeeds or the list of available methods does not | ||||||
|  | 		// contain the "publickey" method, do not attempt to authenticate with any | ||||||
|  | 		// other keys.  According to RFC 4252 Section 7, the latter can occur when | ||||||
|  | 		// additional authentication methods are required. | ||||||
|  | 		if success || !containsMethod(methods, cb.method()) { | ||||||
|  | 			return success, methods, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return false, methods, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func containsMethod(methods []string, method string) bool { | ||||||
|  | 	for _, m := range methods { | ||||||
|  | 		if m == method { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // validateKey validates the key provided is acceptable to the server. | ||||||
|  | func validateKey(key PublicKey, user string, c packetConn) (bool, error) { | ||||||
|  | 	pubKey := key.Marshal() | ||||||
|  | 	msg := publickeyAuthMsg{ | ||||||
|  | 		User:     user, | ||||||
|  | 		Service:  serviceSSH, | ||||||
|  | 		Method:   "publickey", | ||||||
|  | 		HasSig:   false, | ||||||
|  | 		Algoname: key.Type(), | ||||||
|  | 		PubKey:   pubKey, | ||||||
|  | 	} | ||||||
|  | 	if err := c.writePacket(Marshal(&msg)); err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return confirmKeyAck(key, c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func confirmKeyAck(key PublicKey, c packetConn) (bool, error) { | ||||||
|  | 	pubKey := key.Marshal() | ||||||
|  | 	algoname := key.Type() | ||||||
|  |  | ||||||
|  | 	for { | ||||||
|  | 		packet, err := c.readPacket() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, err | ||||||
|  | 		} | ||||||
|  | 		switch packet[0] { | ||||||
|  | 		case msgUserAuthBanner: | ||||||
|  | 			if err := handleBannerResponse(c, packet); err != nil { | ||||||
|  | 				return false, err | ||||||
|  | 			} | ||||||
|  | 		case msgUserAuthPubKeyOk: | ||||||
|  | 			var msg userAuthPubKeyOkMsg | ||||||
|  | 			if err := Unmarshal(packet, &msg); err != nil { | ||||||
|  | 				return false, err | ||||||
|  | 			} | ||||||
|  | 			if msg.Algo != algoname || !bytes.Equal(msg.PubKey, pubKey) { | ||||||
|  | 				return false, nil | ||||||
|  | 			} | ||||||
|  | 			return true, nil | ||||||
|  | 		case msgUserAuthFailure: | ||||||
|  | 			return false, nil | ||||||
|  | 		default: | ||||||
|  | 			return false, unexpectedMessageError(msgUserAuthSuccess, packet[0]) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PublicKeys returns an AuthMethod that uses the given key | ||||||
|  | // pairs. | ||||||
|  | func PublicKeys(signers ...Signer) AuthMethod { | ||||||
|  | 	return publicKeyCallback(func() ([]Signer, error) { return signers, nil }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PublicKeysCallback returns an AuthMethod that runs the given | ||||||
|  | // function to obtain a list of key pairs. | ||||||
|  | func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod { | ||||||
|  | 	return publicKeyCallback(getSigners) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // handleAuthResponse returns whether the preceding authentication request succeeded | ||||||
|  | // along with a list of remaining authentication methods to try next and | ||||||
|  | // an error if an unexpected response was received. | ||||||
|  | func handleAuthResponse(c packetConn) (bool, []string, error) { | ||||||
|  | 	for { | ||||||
|  | 		packet, err := c.readPacket() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		switch packet[0] { | ||||||
|  | 		case msgUserAuthBanner: | ||||||
|  | 			if err := handleBannerResponse(c, packet); err != nil { | ||||||
|  | 				return false, nil, err | ||||||
|  | 			} | ||||||
|  | 		case msgUserAuthFailure: | ||||||
|  | 			var msg userAuthFailureMsg | ||||||
|  | 			if err := Unmarshal(packet, &msg); err != nil { | ||||||
|  | 				return false, nil, err | ||||||
|  | 			} | ||||||
|  | 			return false, msg.Methods, nil | ||||||
|  | 		case msgUserAuthSuccess: | ||||||
|  | 			return true, nil, nil | ||||||
|  | 		default: | ||||||
|  | 			return false, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func handleBannerResponse(c packetConn, packet []byte) error { | ||||||
|  | 	var msg userAuthBannerMsg | ||||||
|  | 	if err := Unmarshal(packet, &msg); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	transport, ok := c.(*handshakeTransport) | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if transport.bannerCallback != nil { | ||||||
|  | 		return transport.bannerCallback(msg.Message) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // KeyboardInteractiveChallenge should print questions, optionally | ||||||
|  | // disabling echoing (e.g. for passwords), and return all the answers. | ||||||
|  | // Challenge may be called multiple times in a single session. After | ||||||
|  | // successful authentication, the server may send a challenge with no | ||||||
|  | // questions, for which the user and instruction messages should be | ||||||
|  | // printed.  RFC 4256 section 3.3 details how the UI should behave for | ||||||
|  | // both CLI and GUI environments. | ||||||
|  | type KeyboardInteractiveChallenge func(user, instruction string, questions []string, echos []bool) (answers []string, err error) | ||||||
|  |  | ||||||
|  | // KeyboardInteractive returns an AuthMethod using a prompt/response | ||||||
|  | // sequence controlled by the server. | ||||||
|  | func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod { | ||||||
|  | 	return challenge | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (cb KeyboardInteractiveChallenge) method() string { | ||||||
|  | 	return "keyboard-interactive" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { | ||||||
|  | 	type initiateMsg struct { | ||||||
|  | 		User       string `sshtype:"50"` | ||||||
|  | 		Service    string | ||||||
|  | 		Method     string | ||||||
|  | 		Language   string | ||||||
|  | 		Submethods string | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := c.writePacket(Marshal(&initiateMsg{ | ||||||
|  | 		User:    user, | ||||||
|  | 		Service: serviceSSH, | ||||||
|  | 		Method:  "keyboard-interactive", | ||||||
|  | 	})); err != nil { | ||||||
|  | 		return false, nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for { | ||||||
|  | 		packet, err := c.readPacket() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// like handleAuthResponse, but with less options. | ||||||
|  | 		switch packet[0] { | ||||||
|  | 		case msgUserAuthBanner: | ||||||
|  | 			if err := handleBannerResponse(c, packet); err != nil { | ||||||
|  | 				return false, nil, err | ||||||
|  | 			} | ||||||
|  | 			continue | ||||||
|  | 		case msgUserAuthInfoRequest: | ||||||
|  | 			// OK | ||||||
|  | 		case msgUserAuthFailure: | ||||||
|  | 			var msg userAuthFailureMsg | ||||||
|  | 			if err := Unmarshal(packet, &msg); err != nil { | ||||||
|  | 				return false, nil, err | ||||||
|  | 			} | ||||||
|  | 			return false, msg.Methods, nil | ||||||
|  | 		case msgUserAuthSuccess: | ||||||
|  | 			return true, nil, nil | ||||||
|  | 		default: | ||||||
|  | 			return false, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var msg userAuthInfoRequestMsg | ||||||
|  | 		if err := Unmarshal(packet, &msg); err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Manually unpack the prompt/echo pairs. | ||||||
|  | 		rest := msg.Prompts | ||||||
|  | 		var prompts []string | ||||||
|  | 		var echos []bool | ||||||
|  | 		for i := 0; i < int(msg.NumPrompts); i++ { | ||||||
|  | 			prompt, r, ok := parseString(rest) | ||||||
|  | 			if !ok || len(r) == 0 { | ||||||
|  | 				return false, nil, errors.New("ssh: prompt format error") | ||||||
|  | 			} | ||||||
|  | 			prompts = append(prompts, string(prompt)) | ||||||
|  | 			echos = append(echos, r[0] != 0) | ||||||
|  | 			rest = r[1:] | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if len(rest) != 0 { | ||||||
|  | 			return false, nil, errors.New("ssh: extra data following keyboard-interactive pairs") | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		answers, err := cb(msg.User, msg.Instruction, prompts, echos) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if len(answers) != len(prompts) { | ||||||
|  | 			return false, nil, errors.New("ssh: not enough answers from keyboard-interactive callback") | ||||||
|  | 		} | ||||||
|  | 		responseLength := 1 + 4 | ||||||
|  | 		for _, a := range answers { | ||||||
|  | 			responseLength += stringLength(len(a)) | ||||||
|  | 		} | ||||||
|  | 		serialized := make([]byte, responseLength) | ||||||
|  | 		p := serialized | ||||||
|  | 		p[0] = msgUserAuthInfoResponse | ||||||
|  | 		p = p[1:] | ||||||
|  | 		p = marshalUint32(p, uint32(len(answers))) | ||||||
|  | 		for _, a := range answers { | ||||||
|  | 			p = marshalString(p, []byte(a)) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if err := c.writePacket(serialized); err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type retryableAuthMethod struct { | ||||||
|  | 	authMethod AuthMethod | ||||||
|  | 	maxTries   int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok bool, methods []string, err error) { | ||||||
|  | 	for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ { | ||||||
|  | 		ok, methods, err = r.authMethod.auth(session, user, c, rand) | ||||||
|  | 		if ok || err != nil { // either success or error terminate | ||||||
|  | 			return ok, methods, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return ok, methods, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *retryableAuthMethod) method() string { | ||||||
|  | 	return r.authMethod.method() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RetryableAuthMethod is a decorator for other auth methods enabling them to | ||||||
|  | // be retried up to maxTries before considering that AuthMethod itself failed. | ||||||
|  | // If maxTries is <= 0, will retry indefinitely | ||||||
|  | // | ||||||
|  | // This is useful for interactive clients using challenge/response type | ||||||
|  | // authentication (e.g. Keyboard-Interactive, Password, etc) where the user | ||||||
|  | // could mistype their response resulting in the server issuing a | ||||||
|  | // SSH_MSG_USERAUTH_FAILURE (rfc4252 #8 [password] and rfc4256 #3.4 | ||||||
|  | // [keyboard-interactive]); Without this decorator, the non-retryable | ||||||
|  | // AuthMethod would be removed from future consideration, and never tried again | ||||||
|  | // (and so the user would never be able to retry their entry). | ||||||
|  | func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod { | ||||||
|  | 	return &retryableAuthMethod{authMethod: auth, maxTries: maxTries} | ||||||
|  | } | ||||||
							
								
								
									
										373
									
								
								vendor/golang.org/x/crypto/ssh/common.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								vendor/golang.org/x/crypto/ssh/common.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,373 @@ | |||||||
|  | // 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 ( | ||||||
|  | 	"crypto" | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"math" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
|  | 	_ "crypto/sha1" | ||||||
|  | 	_ "crypto/sha256" | ||||||
|  | 	_ "crypto/sha512" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // These are string constants in the SSH protocol. | ||||||
|  | const ( | ||||||
|  | 	compressionNone = "none" | ||||||
|  | 	serviceUserAuth = "ssh-userauth" | ||||||
|  | 	serviceSSH      = "ssh-connection" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // supportedCiphers specifies the supported ciphers in preference order. | ||||||
|  | var supportedCiphers = []string{ | ||||||
|  | 	"aes128-ctr", "aes192-ctr", "aes256-ctr", | ||||||
|  | 	"aes128-gcm@openssh.com", | ||||||
|  | 	"arcfour256", "arcfour128", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // supportedKexAlgos specifies the supported key-exchange algorithms in | ||||||
|  | // preference order. | ||||||
|  | var supportedKexAlgos = []string{ | ||||||
|  | 	kexAlgoCurve25519SHA256, | ||||||
|  | 	// P384 and P521 are not constant-time yet, but since we don't | ||||||
|  | 	// reuse ephemeral keys, using them for ECDH should be OK. | ||||||
|  | 	kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, | ||||||
|  | 	kexAlgoDH14SHA1, kexAlgoDH1SHA1, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods | ||||||
|  | // of authenticating servers) in preference order. | ||||||
|  | var supportedHostKeyAlgos = []string{ | ||||||
|  | 	CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, | ||||||
|  | 	CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01, | ||||||
|  |  | ||||||
|  | 	KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, | ||||||
|  | 	KeyAlgoRSA, KeyAlgoDSA, | ||||||
|  |  | ||||||
|  | 	KeyAlgoED25519, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // supportedMACs specifies a default set of MAC algorithms in preference order. | ||||||
|  | // This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed | ||||||
|  | // because they have reached the end of their useful life. | ||||||
|  | var supportedMACs = []string{ | ||||||
|  | 	"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var supportedCompressions = []string{compressionNone} | ||||||
|  |  | ||||||
|  | // hashFuncs keeps the mapping of supported algorithms to their respective | ||||||
|  | // hashes needed for signature verification. | ||||||
|  | var hashFuncs = map[string]crypto.Hash{ | ||||||
|  | 	KeyAlgoRSA:          crypto.SHA1, | ||||||
|  | 	KeyAlgoDSA:          crypto.SHA1, | ||||||
|  | 	KeyAlgoECDSA256:     crypto.SHA256, | ||||||
|  | 	KeyAlgoECDSA384:     crypto.SHA384, | ||||||
|  | 	KeyAlgoECDSA521:     crypto.SHA512, | ||||||
|  | 	CertAlgoRSAv01:      crypto.SHA1, | ||||||
|  | 	CertAlgoDSAv01:      crypto.SHA1, | ||||||
|  | 	CertAlgoECDSA256v01: crypto.SHA256, | ||||||
|  | 	CertAlgoECDSA384v01: crypto.SHA384, | ||||||
|  | 	CertAlgoECDSA521v01: crypto.SHA512, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // unexpectedMessageError results when the SSH message that we received didn't | ||||||
|  | // match what we wanted. | ||||||
|  | func unexpectedMessageError(expected, got uint8) error { | ||||||
|  | 	return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // parseError results from a malformed SSH message. | ||||||
|  | func parseError(tag uint8) error { | ||||||
|  | 	return fmt.Errorf("ssh: parse error in message type %d", tag) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func findCommon(what string, client []string, server []string) (common string, err error) { | ||||||
|  | 	for _, c := range client { | ||||||
|  | 		for _, s := range server { | ||||||
|  | 			if c == s { | ||||||
|  | 				return c, nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type directionAlgorithms struct { | ||||||
|  | 	Cipher      string | ||||||
|  | 	MAC         string | ||||||
|  | 	Compression string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // rekeyBytes returns a rekeying intervals in bytes. | ||||||
|  | func (a *directionAlgorithms) rekeyBytes() int64 { | ||||||
|  | 	// According to RFC4344 block ciphers should rekey after | ||||||
|  | 	// 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is | ||||||
|  | 	// 128. | ||||||
|  | 	switch a.Cipher { | ||||||
|  | 	case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcmCipherID, aes128cbcID: | ||||||
|  | 		return 16 * (1 << 32) | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// For others, stick with RFC4253 recommendation to rekey after 1 Gb of data. | ||||||
|  | 	return 1 << 30 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type algorithms struct { | ||||||
|  | 	kex     string | ||||||
|  | 	hostKey string | ||||||
|  | 	w       directionAlgorithms | ||||||
|  | 	r       directionAlgorithms | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { | ||||||
|  | 	result := &algorithms{} | ||||||
|  |  | ||||||
|  | 	result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	result.w.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	result.r.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	result.w.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	result.r.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	result.w.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	result.r.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return result, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // If rekeythreshold is too small, we can't make any progress sending | ||||||
|  | // stuff. | ||||||
|  | const minRekeyThreshold uint64 = 256 | ||||||
|  |  | ||||||
|  | // Config contains configuration data common to both ServerConfig and | ||||||
|  | // ClientConfig. | ||||||
|  | type Config struct { | ||||||
|  | 	// Rand provides the source of entropy for cryptographic | ||||||
|  | 	// primitives. If Rand is nil, the cryptographic random reader | ||||||
|  | 	// in package crypto/rand will be used. | ||||||
|  | 	Rand io.Reader | ||||||
|  |  | ||||||
|  | 	// The maximum number of bytes sent or received after which a | ||||||
|  | 	// new key is negotiated. It must be at least 256. If | ||||||
|  | 	// unspecified, a size suitable for the chosen cipher is used. | ||||||
|  | 	RekeyThreshold uint64 | ||||||
|  |  | ||||||
|  | 	// The allowed key exchanges algorithms. If unspecified then a | ||||||
|  | 	// default set of algorithms is used. | ||||||
|  | 	KeyExchanges []string | ||||||
|  |  | ||||||
|  | 	// The allowed cipher algorithms. If unspecified then a sensible | ||||||
|  | 	// default is used. | ||||||
|  | 	Ciphers []string | ||||||
|  |  | ||||||
|  | 	// The allowed MAC algorithms. If unspecified then a sensible default | ||||||
|  | 	// is used. | ||||||
|  | 	MACs []string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetDefaults sets sensible values for unset fields in config. This is | ||||||
|  | // exported for testing: Configs passed to SSH functions are copied and have | ||||||
|  | // default values set automatically. | ||||||
|  | func (c *Config) SetDefaults() { | ||||||
|  | 	if c.Rand == nil { | ||||||
|  | 		c.Rand = rand.Reader | ||||||
|  | 	} | ||||||
|  | 	if c.Ciphers == nil { | ||||||
|  | 		c.Ciphers = supportedCiphers | ||||||
|  | 	} | ||||||
|  | 	var ciphers []string | ||||||
|  | 	for _, c := range c.Ciphers { | ||||||
|  | 		if cipherModes[c] != nil { | ||||||
|  | 			// reject the cipher if we have no cipherModes definition | ||||||
|  | 			ciphers = append(ciphers, c) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	c.Ciphers = ciphers | ||||||
|  |  | ||||||
|  | 	if c.KeyExchanges == nil { | ||||||
|  | 		c.KeyExchanges = supportedKexAlgos | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if c.MACs == nil { | ||||||
|  | 		c.MACs = supportedMACs | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if c.RekeyThreshold == 0 { | ||||||
|  | 		// cipher specific default | ||||||
|  | 	} else if c.RekeyThreshold < minRekeyThreshold { | ||||||
|  | 		c.RekeyThreshold = minRekeyThreshold | ||||||
|  | 	} else if c.RekeyThreshold >= math.MaxInt64 { | ||||||
|  | 		// Avoid weirdness if somebody uses -1 as a threshold. | ||||||
|  | 		c.RekeyThreshold = math.MaxInt64 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // buildDataSignedForAuth returns the data that is signed in order to prove | ||||||
|  | // possession of a private key. See RFC 4252, section 7. | ||||||
|  | func buildDataSignedForAuth(sessionID []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { | ||||||
|  | 	data := struct { | ||||||
|  | 		Session []byte | ||||||
|  | 		Type    byte | ||||||
|  | 		User    string | ||||||
|  | 		Service string | ||||||
|  | 		Method  string | ||||||
|  | 		Sign    bool | ||||||
|  | 		Algo    []byte | ||||||
|  | 		PubKey  []byte | ||||||
|  | 	}{ | ||||||
|  | 		sessionID, | ||||||
|  | 		msgUserAuthRequest, | ||||||
|  | 		req.User, | ||||||
|  | 		req.Service, | ||||||
|  | 		req.Method, | ||||||
|  | 		true, | ||||||
|  | 		algo, | ||||||
|  | 		pubKey, | ||||||
|  | 	} | ||||||
|  | 	return Marshal(data) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func appendU16(buf []byte, n uint16) []byte { | ||||||
|  | 	return append(buf, byte(n>>8), byte(n)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func appendU32(buf []byte, n uint32) []byte { | ||||||
|  | 	return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func appendU64(buf []byte, n uint64) []byte { | ||||||
|  | 	return append(buf, | ||||||
|  | 		byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), | ||||||
|  | 		byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func appendInt(buf []byte, n int) []byte { | ||||||
|  | 	return appendU32(buf, uint32(n)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func appendString(buf []byte, s string) []byte { | ||||||
|  | 	buf = appendU32(buf, uint32(len(s))) | ||||||
|  | 	buf = append(buf, s...) | ||||||
|  | 	return buf | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func appendBool(buf []byte, b bool) []byte { | ||||||
|  | 	if b { | ||||||
|  | 		return append(buf, 1) | ||||||
|  | 	} | ||||||
|  | 	return append(buf, 0) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // newCond is a helper to hide the fact that there is no usable zero | ||||||
|  | // value for sync.Cond. | ||||||
|  | func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) } | ||||||
|  |  | ||||||
|  | // window represents the buffer available to clients | ||||||
|  | // wishing to write to a channel. | ||||||
|  | type window struct { | ||||||
|  | 	*sync.Cond | ||||||
|  | 	win          uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1 | ||||||
|  | 	writeWaiters int | ||||||
|  | 	closed       bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // add adds win to the amount of window available | ||||||
|  | // for consumers. | ||||||
|  | func (w *window) add(win uint32) bool { | ||||||
|  | 	// a zero sized window adjust is a noop. | ||||||
|  | 	if win == 0 { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	w.L.Lock() | ||||||
|  | 	if w.win+win < win { | ||||||
|  | 		w.L.Unlock() | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	w.win += win | ||||||
|  | 	// It is unusual that multiple goroutines would be attempting to reserve | ||||||
|  | 	// window space, but not guaranteed. Use broadcast to notify all waiters | ||||||
|  | 	// that additional window is available. | ||||||
|  | 	w.Broadcast() | ||||||
|  | 	w.L.Unlock() | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // close sets the window to closed, so all reservations fail | ||||||
|  | // immediately. | ||||||
|  | func (w *window) close() { | ||||||
|  | 	w.L.Lock() | ||||||
|  | 	w.closed = true | ||||||
|  | 	w.Broadcast() | ||||||
|  | 	w.L.Unlock() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // reserve reserves win from the available window capacity. | ||||||
|  | // If no capacity remains, reserve will block. reserve may | ||||||
|  | // return less than requested. | ||||||
|  | func (w *window) reserve(win uint32) (uint32, error) { | ||||||
|  | 	var err error | ||||||
|  | 	w.L.Lock() | ||||||
|  | 	w.writeWaiters++ | ||||||
|  | 	w.Broadcast() | ||||||
|  | 	for w.win == 0 && !w.closed { | ||||||
|  | 		w.Wait() | ||||||
|  | 	} | ||||||
|  | 	w.writeWaiters-- | ||||||
|  | 	if w.win < win { | ||||||
|  | 		win = w.win | ||||||
|  | 	} | ||||||
|  | 	w.win -= win | ||||||
|  | 	if w.closed { | ||||||
|  | 		err = io.EOF | ||||||
|  | 	} | ||||||
|  | 	w.L.Unlock() | ||||||
|  | 	return win, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // waitWriterBlocked waits until some goroutine is blocked for further | ||||||
|  | // writes. It is used in tests only. | ||||||
|  | func (w *window) waitWriterBlocked() { | ||||||
|  | 	w.Cond.L.Lock() | ||||||
|  | 	for w.writeWaiters == 0 { | ||||||
|  | 		w.Cond.Wait() | ||||||
|  | 	} | ||||||
|  | 	w.Cond.L.Unlock() | ||||||
|  | } | ||||||
							
								
								
									
										143
									
								
								vendor/golang.org/x/crypto/ssh/connection.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								vendor/golang.org/x/crypto/ssh/connection.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | |||||||
|  | // Copyright 2013 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 ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"net" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // OpenChannelError is returned if the other side rejects an | ||||||
|  | // OpenChannel request. | ||||||
|  | type OpenChannelError struct { | ||||||
|  | 	Reason  RejectionReason | ||||||
|  | 	Message string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *OpenChannelError) Error() string { | ||||||
|  | 	return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ConnMetadata holds metadata for the connection. | ||||||
|  | type ConnMetadata interface { | ||||||
|  | 	// User returns the user ID for this connection. | ||||||
|  | 	User() string | ||||||
|  |  | ||||||
|  | 	// SessionID returns the session hash, also denoted by H. | ||||||
|  | 	SessionID() []byte | ||||||
|  |  | ||||||
|  | 	// ClientVersion returns the client's version string as hashed | ||||||
|  | 	// into the session ID. | ||||||
|  | 	ClientVersion() []byte | ||||||
|  |  | ||||||
|  | 	// ServerVersion returns the server's version string as hashed | ||||||
|  | 	// into the session ID. | ||||||
|  | 	ServerVersion() []byte | ||||||
|  |  | ||||||
|  | 	// RemoteAddr returns the remote address for this connection. | ||||||
|  | 	RemoteAddr() net.Addr | ||||||
|  |  | ||||||
|  | 	// LocalAddr returns the local address for this connection. | ||||||
|  | 	LocalAddr() net.Addr | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Conn represents an SSH connection for both server and client roles. | ||||||
|  | // Conn is the basis for implementing an application layer, such | ||||||
|  | // as ClientConn, which implements the traditional shell access for | ||||||
|  | // clients. | ||||||
|  | type Conn interface { | ||||||
|  | 	ConnMetadata | ||||||
|  |  | ||||||
|  | 	// SendRequest sends a global request, and returns the | ||||||
|  | 	// reply. If wantReply is true, it returns the response status | ||||||
|  | 	// and payload. See also RFC4254, section 4. | ||||||
|  | 	SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) | ||||||
|  |  | ||||||
|  | 	// OpenChannel tries to open an channel. If the request is | ||||||
|  | 	// rejected, it returns *OpenChannelError. On success it returns | ||||||
|  | 	// the SSH Channel and a Go channel for incoming, out-of-band | ||||||
|  | 	// requests. The Go channel must be serviced, or the | ||||||
|  | 	// connection will hang. | ||||||
|  | 	OpenChannel(name string, data []byte) (Channel, <-chan *Request, error) | ||||||
|  |  | ||||||
|  | 	// Close closes the underlying network connection | ||||||
|  | 	Close() error | ||||||
|  |  | ||||||
|  | 	// Wait blocks until the connection has shut down, and returns the | ||||||
|  | 	// error causing the shutdown. | ||||||
|  | 	Wait() error | ||||||
|  |  | ||||||
|  | 	// TODO(hanwen): consider exposing: | ||||||
|  | 	//   RequestKeyChange | ||||||
|  | 	//   Disconnect | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DiscardRequests consumes and rejects all requests from the | ||||||
|  | // passed-in channel. | ||||||
|  | func DiscardRequests(in <-chan *Request) { | ||||||
|  | 	for req := range in { | ||||||
|  | 		if req.WantReply { | ||||||
|  | 			req.Reply(false, nil) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // A connection represents an incoming connection. | ||||||
|  | type connection struct { | ||||||
|  | 	transport *handshakeTransport | ||||||
|  | 	sshConn | ||||||
|  |  | ||||||
|  | 	// The connection protocol. | ||||||
|  | 	*mux | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *connection) Close() error { | ||||||
|  | 	return c.sshConn.conn.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // sshconn provides net.Conn metadata, but disallows direct reads and | ||||||
|  | // writes. | ||||||
|  | type sshConn struct { | ||||||
|  | 	conn net.Conn | ||||||
|  |  | ||||||
|  | 	user          string | ||||||
|  | 	sessionID     []byte | ||||||
|  | 	clientVersion []byte | ||||||
|  | 	serverVersion []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func dup(src []byte) []byte { | ||||||
|  | 	dst := make([]byte, len(src)) | ||||||
|  | 	copy(dst, src) | ||||||
|  | 	return dst | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sshConn) User() string { | ||||||
|  | 	return c.user | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sshConn) RemoteAddr() net.Addr { | ||||||
|  | 	return c.conn.RemoteAddr() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sshConn) Close() error { | ||||||
|  | 	return c.conn.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sshConn) LocalAddr() net.Addr { | ||||||
|  | 	return c.conn.LocalAddr() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sshConn) SessionID() []byte { | ||||||
|  | 	return dup(c.sessionID) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sshConn) ClientVersion() []byte { | ||||||
|  | 	return dup(c.clientVersion) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sshConn) ServerVersion() []byte { | ||||||
|  | 	return dup(c.serverVersion) | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								vendor/golang.org/x/crypto/ssh/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/golang.org/x/crypto/ssh/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | // 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 implements an SSH client and server. | ||||||
|  |  | ||||||
|  | SSH is a transport security protocol, an authentication protocol and a | ||||||
|  | family of application protocols. The most typical application level | ||||||
|  | protocol is a remote shell and this is specifically implemented.  However, | ||||||
|  | the multiplexed nature of SSH is exposed to users that wish to support | ||||||
|  | others. | ||||||
|  |  | ||||||
|  | References: | ||||||
|  |   [PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD | ||||||
|  |   [SSH-PARAMETERS]:    http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 | ||||||
|  |  | ||||||
|  | This package does not fall under the stability promise of the Go language itself, | ||||||
|  | so its API may be changed when pressing needs arise. | ||||||
|  | */ | ||||||
|  | package ssh // import "golang.org/x/crypto/ssh" | ||||||
							
								
								
									
										646
									
								
								vendor/golang.org/x/crypto/ssh/handshake.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										646
									
								
								vendor/golang.org/x/crypto/ssh/handshake.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,646 @@ | |||||||
|  | // Copyright 2013 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 ( | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"log" | ||||||
|  | 	"net" | ||||||
|  | 	"sync" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // debugHandshake, if set, prints messages sent and received.  Key | ||||||
|  | // exchange messages are printed as if DH were used, so the debug | ||||||
|  | // messages are wrong when using ECDH. | ||||||
|  | const debugHandshake = false | ||||||
|  |  | ||||||
|  | // chanSize sets the amount of buffering SSH connections. This is | ||||||
|  | // primarily for testing: setting chanSize=0 uncovers deadlocks more | ||||||
|  | // quickly. | ||||||
|  | const chanSize = 16 | ||||||
|  |  | ||||||
|  | // keyingTransport is a packet based transport that supports key | ||||||
|  | // changes. It need not be thread-safe. It should pass through | ||||||
|  | // msgNewKeys in both directions. | ||||||
|  | type keyingTransport interface { | ||||||
|  | 	packetConn | ||||||
|  |  | ||||||
|  | 	// prepareKeyChange sets up a key change. The key change for a | ||||||
|  | 	// direction will be effected if a msgNewKeys message is sent | ||||||
|  | 	// or received. | ||||||
|  | 	prepareKeyChange(*algorithms, *kexResult) error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // handshakeTransport implements rekeying on top of a keyingTransport | ||||||
|  | // and offers a thread-safe writePacket() interface. | ||||||
|  | type handshakeTransport struct { | ||||||
|  | 	conn   keyingTransport | ||||||
|  | 	config *Config | ||||||
|  |  | ||||||
|  | 	serverVersion []byte | ||||||
|  | 	clientVersion []byte | ||||||
|  |  | ||||||
|  | 	// hostKeys is non-empty if we are the server. In that case, | ||||||
|  | 	// it contains all host keys that can be used to sign the | ||||||
|  | 	// connection. | ||||||
|  | 	hostKeys []Signer | ||||||
|  |  | ||||||
|  | 	// hostKeyAlgorithms is non-empty if we are the client. In that case, | ||||||
|  | 	// we accept these key types from the server as host key. | ||||||
|  | 	hostKeyAlgorithms []string | ||||||
|  |  | ||||||
|  | 	// On read error, incoming is closed, and readError is set. | ||||||
|  | 	incoming  chan []byte | ||||||
|  | 	readError error | ||||||
|  |  | ||||||
|  | 	mu             sync.Mutex | ||||||
|  | 	writeError     error | ||||||
|  | 	sentInitPacket []byte | ||||||
|  | 	sentInitMsg    *kexInitMsg | ||||||
|  | 	pendingPackets [][]byte // Used when a key exchange is in progress. | ||||||
|  |  | ||||||
|  | 	// If the read loop wants to schedule a kex, it pings this | ||||||
|  | 	// channel, and the write loop will send out a kex | ||||||
|  | 	// message. | ||||||
|  | 	requestKex chan struct{} | ||||||
|  |  | ||||||
|  | 	// If the other side requests or confirms a kex, its kexInit | ||||||
|  | 	// packet is sent here for the write loop to find it. | ||||||
|  | 	startKex chan *pendingKex | ||||||
|  |  | ||||||
|  | 	// data for host key checking | ||||||
|  | 	hostKeyCallback HostKeyCallback | ||||||
|  | 	dialAddress     string | ||||||
|  | 	remoteAddr      net.Addr | ||||||
|  |  | ||||||
|  | 	// bannerCallback is non-empty if we are the client and it has been set in | ||||||
|  | 	// ClientConfig. In that case it is called during the user authentication | ||||||
|  | 	// dance to handle a custom server's message. | ||||||
|  | 	bannerCallback BannerCallback | ||||||
|  |  | ||||||
|  | 	// Algorithms agreed in the last key exchange. | ||||||
|  | 	algorithms *algorithms | ||||||
|  |  | ||||||
|  | 	readPacketsLeft uint32 | ||||||
|  | 	readBytesLeft   int64 | ||||||
|  |  | ||||||
|  | 	writePacketsLeft uint32 | ||||||
|  | 	writeBytesLeft   int64 | ||||||
|  |  | ||||||
|  | 	// The session ID or nil if first kex did not complete yet. | ||||||
|  | 	sessionID []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type pendingKex struct { | ||||||
|  | 	otherInit []byte | ||||||
|  | 	done      chan error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport { | ||||||
|  | 	t := &handshakeTransport{ | ||||||
|  | 		conn:          conn, | ||||||
|  | 		serverVersion: serverVersion, | ||||||
|  | 		clientVersion: clientVersion, | ||||||
|  | 		incoming:      make(chan []byte, chanSize), | ||||||
|  | 		requestKex:    make(chan struct{}, 1), | ||||||
|  | 		startKex:      make(chan *pendingKex, 1), | ||||||
|  |  | ||||||
|  | 		config: config, | ||||||
|  | 	} | ||||||
|  | 	t.resetReadThresholds() | ||||||
|  | 	t.resetWriteThresholds() | ||||||
|  |  | ||||||
|  | 	// We always start with a mandatory key exchange. | ||||||
|  | 	t.requestKex <- struct{}{} | ||||||
|  | 	return t | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport { | ||||||
|  | 	t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) | ||||||
|  | 	t.dialAddress = dialAddr | ||||||
|  | 	t.remoteAddr = addr | ||||||
|  | 	t.hostKeyCallback = config.HostKeyCallback | ||||||
|  | 	t.bannerCallback = config.BannerCallback | ||||||
|  | 	if config.HostKeyAlgorithms != nil { | ||||||
|  | 		t.hostKeyAlgorithms = config.HostKeyAlgorithms | ||||||
|  | 	} else { | ||||||
|  | 		t.hostKeyAlgorithms = supportedHostKeyAlgos | ||||||
|  | 	} | ||||||
|  | 	go t.readLoop() | ||||||
|  | 	go t.kexLoop() | ||||||
|  | 	return t | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport { | ||||||
|  | 	t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) | ||||||
|  | 	t.hostKeys = config.hostKeys | ||||||
|  | 	go t.readLoop() | ||||||
|  | 	go t.kexLoop() | ||||||
|  | 	return t | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) getSessionID() []byte { | ||||||
|  | 	return t.sessionID | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // waitSession waits for the session to be established. This should be | ||||||
|  | // the first thing to call after instantiating handshakeTransport. | ||||||
|  | func (t *handshakeTransport) waitSession() error { | ||||||
|  | 	p, err := t.readPacket() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if p[0] != msgNewKeys { | ||||||
|  | 		return fmt.Errorf("ssh: first packet should be msgNewKeys") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) id() string { | ||||||
|  | 	if len(t.hostKeys) > 0 { | ||||||
|  | 		return "server" | ||||||
|  | 	} | ||||||
|  | 	return "client" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) printPacket(p []byte, write bool) { | ||||||
|  | 	action := "got" | ||||||
|  | 	if write { | ||||||
|  | 		action = "sent" | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if p[0] == msgChannelData || p[0] == msgChannelExtendedData { | ||||||
|  | 		log.Printf("%s %s data (packet %d bytes)", t.id(), action, len(p)) | ||||||
|  | 	} else { | ||||||
|  | 		msg, err := decode(p) | ||||||
|  | 		log.Printf("%s %s %T %v (%v)", t.id(), action, msg, msg, err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) readPacket() ([]byte, error) { | ||||||
|  | 	p, ok := <-t.incoming | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, t.readError | ||||||
|  | 	} | ||||||
|  | 	return p, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) readLoop() { | ||||||
|  | 	first := true | ||||||
|  | 	for { | ||||||
|  | 		p, err := t.readOnePacket(first) | ||||||
|  | 		first = false | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.readError = err | ||||||
|  | 			close(t.incoming) | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		if p[0] == msgIgnore || p[0] == msgDebug { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		t.incoming <- p | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Stop writers too. | ||||||
|  | 	t.recordWriteError(t.readError) | ||||||
|  |  | ||||||
|  | 	// Unblock the writer should it wait for this. | ||||||
|  | 	close(t.startKex) | ||||||
|  |  | ||||||
|  | 	// Don't close t.requestKex; it's also written to from writePacket. | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) pushPacket(p []byte) error { | ||||||
|  | 	if debugHandshake { | ||||||
|  | 		t.printPacket(p, true) | ||||||
|  | 	} | ||||||
|  | 	return t.conn.writePacket(p) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) getWriteError() error { | ||||||
|  | 	t.mu.Lock() | ||||||
|  | 	defer t.mu.Unlock() | ||||||
|  | 	return t.writeError | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) recordWriteError(err error) { | ||||||
|  | 	t.mu.Lock() | ||||||
|  | 	defer t.mu.Unlock() | ||||||
|  | 	if t.writeError == nil && err != nil { | ||||||
|  | 		t.writeError = err | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) requestKeyExchange() { | ||||||
|  | 	select { | ||||||
|  | 	case t.requestKex <- struct{}{}: | ||||||
|  | 	default: | ||||||
|  | 		// something already requested a kex, so do nothing. | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) resetWriteThresholds() { | ||||||
|  | 	t.writePacketsLeft = packetRekeyThreshold | ||||||
|  | 	if t.config.RekeyThreshold > 0 { | ||||||
|  | 		t.writeBytesLeft = int64(t.config.RekeyThreshold) | ||||||
|  | 	} else if t.algorithms != nil { | ||||||
|  | 		t.writeBytesLeft = t.algorithms.w.rekeyBytes() | ||||||
|  | 	} else { | ||||||
|  | 		t.writeBytesLeft = 1 << 30 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) kexLoop() { | ||||||
|  |  | ||||||
|  | write: | ||||||
|  | 	for t.getWriteError() == nil { | ||||||
|  | 		var request *pendingKex | ||||||
|  | 		var sent bool | ||||||
|  |  | ||||||
|  | 		for request == nil || !sent { | ||||||
|  | 			var ok bool | ||||||
|  | 			select { | ||||||
|  | 			case request, ok = <-t.startKex: | ||||||
|  | 				if !ok { | ||||||
|  | 					break write | ||||||
|  | 				} | ||||||
|  | 			case <-t.requestKex: | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if !sent { | ||||||
|  | 				if err := t.sendKexInit(); err != nil { | ||||||
|  | 					t.recordWriteError(err) | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 				sent = true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if err := t.getWriteError(); err != nil { | ||||||
|  | 			if request != nil { | ||||||
|  | 				request.done <- err | ||||||
|  | 			} | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// We're not servicing t.requestKex, but that is OK: | ||||||
|  | 		// we never block on sending to t.requestKex. | ||||||
|  |  | ||||||
|  | 		// We're not servicing t.startKex, but the remote end | ||||||
|  | 		// has just sent us a kexInitMsg, so it can't send | ||||||
|  | 		// another key change request, until we close the done | ||||||
|  | 		// channel on the pendingKex request. | ||||||
|  |  | ||||||
|  | 		err := t.enterKeyExchange(request.otherInit) | ||||||
|  |  | ||||||
|  | 		t.mu.Lock() | ||||||
|  | 		t.writeError = err | ||||||
|  | 		t.sentInitPacket = nil | ||||||
|  | 		t.sentInitMsg = nil | ||||||
|  |  | ||||||
|  | 		t.resetWriteThresholds() | ||||||
|  |  | ||||||
|  | 		// we have completed the key exchange. Since the | ||||||
|  | 		// reader is still blocked, it is safe to clear out | ||||||
|  | 		// the requestKex channel. This avoids the situation | ||||||
|  | 		// where: 1) we consumed our own request for the | ||||||
|  | 		// initial kex, and 2) the kex from the remote side | ||||||
|  | 		// caused another send on the requestKex channel, | ||||||
|  | 	clear: | ||||||
|  | 		for { | ||||||
|  | 			select { | ||||||
|  | 			case <-t.requestKex: | ||||||
|  | 				// | ||||||
|  | 			default: | ||||||
|  | 				break clear | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		request.done <- t.writeError | ||||||
|  |  | ||||||
|  | 		// kex finished. Push packets that we received while | ||||||
|  | 		// the kex was in progress. Don't look at t.startKex | ||||||
|  | 		// and don't increment writtenSinceKex: if we trigger | ||||||
|  | 		// another kex while we are still busy with the last | ||||||
|  | 		// one, things will become very confusing. | ||||||
|  | 		for _, p := range t.pendingPackets { | ||||||
|  | 			t.writeError = t.pushPacket(p) | ||||||
|  | 			if t.writeError != nil { | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		t.pendingPackets = t.pendingPackets[:0] | ||||||
|  | 		t.mu.Unlock() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// drain startKex channel. We don't service t.requestKex | ||||||
|  | 	// because nobody does blocking sends there. | ||||||
|  | 	go func() { | ||||||
|  | 		for init := range t.startKex { | ||||||
|  | 			init.done <- t.writeError | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	// Unblock reader. | ||||||
|  | 	t.conn.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // The protocol uses uint32 for packet counters, so we can't let them | ||||||
|  | // reach 1<<32.  We will actually read and write more packets than | ||||||
|  | // this, though: the other side may send more packets, and after we | ||||||
|  | // hit this limit on writing we will send a few more packets for the | ||||||
|  | // key exchange itself. | ||||||
|  | const packetRekeyThreshold = (1 << 31) | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) resetReadThresholds() { | ||||||
|  | 	t.readPacketsLeft = packetRekeyThreshold | ||||||
|  | 	if t.config.RekeyThreshold > 0 { | ||||||
|  | 		t.readBytesLeft = int64(t.config.RekeyThreshold) | ||||||
|  | 	} else if t.algorithms != nil { | ||||||
|  | 		t.readBytesLeft = t.algorithms.r.rekeyBytes() | ||||||
|  | 	} else { | ||||||
|  | 		t.readBytesLeft = 1 << 30 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) { | ||||||
|  | 	p, err := t.conn.readPacket() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if t.readPacketsLeft > 0 { | ||||||
|  | 		t.readPacketsLeft-- | ||||||
|  | 	} else { | ||||||
|  | 		t.requestKeyExchange() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if t.readBytesLeft > 0 { | ||||||
|  | 		t.readBytesLeft -= int64(len(p)) | ||||||
|  | 	} else { | ||||||
|  | 		t.requestKeyExchange() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if debugHandshake { | ||||||
|  | 		t.printPacket(p, false) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if first && p[0] != msgKexInit { | ||||||
|  | 		return nil, fmt.Errorf("ssh: first packet should be msgKexInit") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if p[0] != msgKexInit { | ||||||
|  | 		return p, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	firstKex := t.sessionID == nil | ||||||
|  |  | ||||||
|  | 	kex := pendingKex{ | ||||||
|  | 		done:      make(chan error, 1), | ||||||
|  | 		otherInit: p, | ||||||
|  | 	} | ||||||
|  | 	t.startKex <- &kex | ||||||
|  | 	err = <-kex.done | ||||||
|  |  | ||||||
|  | 	if debugHandshake { | ||||||
|  | 		log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	t.resetReadThresholds() | ||||||
|  |  | ||||||
|  | 	// By default, a key exchange is hidden from higher layers by | ||||||
|  | 	// translating it into msgIgnore. | ||||||
|  | 	successPacket := []byte{msgIgnore} | ||||||
|  | 	if firstKex { | ||||||
|  | 		// sendKexInit() for the first kex waits for | ||||||
|  | 		// msgNewKeys so the authentication process is | ||||||
|  | 		// guaranteed to happen over an encrypted transport. | ||||||
|  | 		successPacket = []byte{msgNewKeys} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return successPacket, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // sendKexInit sends a key change message. | ||||||
|  | func (t *handshakeTransport) sendKexInit() error { | ||||||
|  | 	t.mu.Lock() | ||||||
|  | 	defer t.mu.Unlock() | ||||||
|  | 	if t.sentInitMsg != nil { | ||||||
|  | 		// kexInits may be sent either in response to the other side, | ||||||
|  | 		// or because our side wants to initiate a key change, so we | ||||||
|  | 		// may have already sent a kexInit. In that case, don't send a | ||||||
|  | 		// second kexInit. | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	msg := &kexInitMsg{ | ||||||
|  | 		KexAlgos:                t.config.KeyExchanges, | ||||||
|  | 		CiphersClientServer:     t.config.Ciphers, | ||||||
|  | 		CiphersServerClient:     t.config.Ciphers, | ||||||
|  | 		MACsClientServer:        t.config.MACs, | ||||||
|  | 		MACsServerClient:        t.config.MACs, | ||||||
|  | 		CompressionClientServer: supportedCompressions, | ||||||
|  | 		CompressionServerClient: supportedCompressions, | ||||||
|  | 	} | ||||||
|  | 	io.ReadFull(rand.Reader, msg.Cookie[:]) | ||||||
|  |  | ||||||
|  | 	if len(t.hostKeys) > 0 { | ||||||
|  | 		for _, k := range t.hostKeys { | ||||||
|  | 			msg.ServerHostKeyAlgos = append( | ||||||
|  | 				msg.ServerHostKeyAlgos, k.PublicKey().Type()) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		msg.ServerHostKeyAlgos = t.hostKeyAlgorithms | ||||||
|  | 	} | ||||||
|  | 	packet := Marshal(msg) | ||||||
|  |  | ||||||
|  | 	// writePacket destroys the contents, so save a copy. | ||||||
|  | 	packetCopy := make([]byte, len(packet)) | ||||||
|  | 	copy(packetCopy, packet) | ||||||
|  |  | ||||||
|  | 	if err := t.pushPacket(packetCopy); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	t.sentInitMsg = msg | ||||||
|  | 	t.sentInitPacket = packet | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) writePacket(p []byte) error { | ||||||
|  | 	switch p[0] { | ||||||
|  | 	case msgKexInit: | ||||||
|  | 		return errors.New("ssh: only handshakeTransport can send kexInit") | ||||||
|  | 	case msgNewKeys: | ||||||
|  | 		return errors.New("ssh: only handshakeTransport can send newKeys") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	t.mu.Lock() | ||||||
|  | 	defer t.mu.Unlock() | ||||||
|  | 	if t.writeError != nil { | ||||||
|  | 		return t.writeError | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if t.sentInitMsg != nil { | ||||||
|  | 		// Copy the packet so the writer can reuse the buffer. | ||||||
|  | 		cp := make([]byte, len(p)) | ||||||
|  | 		copy(cp, p) | ||||||
|  | 		t.pendingPackets = append(t.pendingPackets, cp) | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if t.writeBytesLeft > 0 { | ||||||
|  | 		t.writeBytesLeft -= int64(len(p)) | ||||||
|  | 	} else { | ||||||
|  | 		t.requestKeyExchange() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if t.writePacketsLeft > 0 { | ||||||
|  | 		t.writePacketsLeft-- | ||||||
|  | 	} else { | ||||||
|  | 		t.requestKeyExchange() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := t.pushPacket(p); err != nil { | ||||||
|  | 		t.writeError = err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) Close() error { | ||||||
|  | 	return t.conn.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { | ||||||
|  | 	if debugHandshake { | ||||||
|  | 		log.Printf("%s entered key exchange", t.id()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	otherInit := &kexInitMsg{} | ||||||
|  | 	if err := Unmarshal(otherInitPacket, otherInit); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	magics := handshakeMagics{ | ||||||
|  | 		clientVersion: t.clientVersion, | ||||||
|  | 		serverVersion: t.serverVersion, | ||||||
|  | 		clientKexInit: otherInitPacket, | ||||||
|  | 		serverKexInit: t.sentInitPacket, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	clientInit := otherInit | ||||||
|  | 	serverInit := t.sentInitMsg | ||||||
|  | 	if len(t.hostKeys) == 0 { | ||||||
|  | 		clientInit, serverInit = serverInit, clientInit | ||||||
|  |  | ||||||
|  | 		magics.clientKexInit = t.sentInitPacket | ||||||
|  | 		magics.serverKexInit = otherInitPacket | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var err error | ||||||
|  | 	t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// We don't send FirstKexFollows, but we handle receiving it. | ||||||
|  | 	// | ||||||
|  | 	// RFC 4253 section 7 defines the kex and the agreement method for | ||||||
|  | 	// first_kex_packet_follows. It states that the guessed packet | ||||||
|  | 	// should be ignored if the "kex algorithm and/or the host | ||||||
|  | 	// key algorithm is guessed wrong (server and client have | ||||||
|  | 	// different preferred algorithm), or if any of the other | ||||||
|  | 	// algorithms cannot be agreed upon". The other algorithms have | ||||||
|  | 	// already been checked above so the kex algorithm and host key | ||||||
|  | 	// algorithm are checked here. | ||||||
|  | 	if otherInit.FirstKexFollows && (clientInit.KexAlgos[0] != serverInit.KexAlgos[0] || clientInit.ServerHostKeyAlgos[0] != serverInit.ServerHostKeyAlgos[0]) { | ||||||
|  | 		// other side sent a kex message for the wrong algorithm, | ||||||
|  | 		// which we have to ignore. | ||||||
|  | 		if _, err := t.conn.readPacket(); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kex, ok := kexAlgoMap[t.algorithms.kex] | ||||||
|  | 	if !ok { | ||||||
|  | 		return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.kex) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var result *kexResult | ||||||
|  | 	if len(t.hostKeys) > 0 { | ||||||
|  | 		result, err = t.server(kex, t.algorithms, &magics) | ||||||
|  | 	} else { | ||||||
|  | 		result, err = t.client(kex, t.algorithms, &magics) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if t.sessionID == nil { | ||||||
|  | 		t.sessionID = result.H | ||||||
|  | 	} | ||||||
|  | 	result.SessionID = t.sessionID | ||||||
|  |  | ||||||
|  | 	if err := t.conn.prepareKeyChange(t.algorithms, result); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if packet, err := t.conn.readPacket(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} else if packet[0] != msgNewKeys { | ||||||
|  | 		return unexpectedMessageError(msgNewKeys, packet[0]) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { | ||||||
|  | 	var hostKey Signer | ||||||
|  | 	for _, k := range t.hostKeys { | ||||||
|  | 		if algs.hostKey == k.PublicKey().Type() { | ||||||
|  | 			hostKey = k | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey) | ||||||
|  | 	return r, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { | ||||||
|  | 	result, err := kex.Client(t.conn, t.config.Rand, magics) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	hostKey, err := ParsePublicKey(result.HostKey) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := verifyHostKeySignature(hostKey, result); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return result, nil | ||||||
|  | } | ||||||
							
								
								
									
										540
									
								
								vendor/golang.org/x/crypto/ssh/kex.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										540
									
								
								vendor/golang.org/x/crypto/ssh/kex.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,540 @@ | |||||||
|  | // Copyright 2013 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 ( | ||||||
|  | 	"crypto" | ||||||
|  | 	"crypto/ecdsa" | ||||||
|  | 	"crypto/elliptic" | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"crypto/subtle" | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | 	"math/big" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/crypto/curve25519" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	kexAlgoDH1SHA1          = "diffie-hellman-group1-sha1" | ||||||
|  | 	kexAlgoDH14SHA1         = "diffie-hellman-group14-sha1" | ||||||
|  | 	kexAlgoECDH256          = "ecdh-sha2-nistp256" | ||||||
|  | 	kexAlgoECDH384          = "ecdh-sha2-nistp384" | ||||||
|  | 	kexAlgoECDH521          = "ecdh-sha2-nistp521" | ||||||
|  | 	kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // kexResult captures the outcome of a key exchange. | ||||||
|  | type kexResult struct { | ||||||
|  | 	// Session hash. See also RFC 4253, section 8. | ||||||
|  | 	H []byte | ||||||
|  |  | ||||||
|  | 	// Shared secret. See also RFC 4253, section 8. | ||||||
|  | 	K []byte | ||||||
|  |  | ||||||
|  | 	// Host key as hashed into H. | ||||||
|  | 	HostKey []byte | ||||||
|  |  | ||||||
|  | 	// Signature of H. | ||||||
|  | 	Signature []byte | ||||||
|  |  | ||||||
|  | 	// A cryptographic hash function that matches the security | ||||||
|  | 	// level of the key exchange algorithm. It is used for | ||||||
|  | 	// calculating H, and for deriving keys from H and K. | ||||||
|  | 	Hash crypto.Hash | ||||||
|  |  | ||||||
|  | 	// The session ID, which is the first H computed. This is used | ||||||
|  | 	// to derive key material inside the transport. | ||||||
|  | 	SessionID []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // handshakeMagics contains data that is always included in the | ||||||
|  | // session hash. | ||||||
|  | type handshakeMagics struct { | ||||||
|  | 	clientVersion, serverVersion []byte | ||||||
|  | 	clientKexInit, serverKexInit []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *handshakeMagics) write(w io.Writer) { | ||||||
|  | 	writeString(w, m.clientVersion) | ||||||
|  | 	writeString(w, m.serverVersion) | ||||||
|  | 	writeString(w, m.clientKexInit) | ||||||
|  | 	writeString(w, m.serverKexInit) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // kexAlgorithm abstracts different key exchange algorithms. | ||||||
|  | type kexAlgorithm interface { | ||||||
|  | 	// Server runs server-side key agreement, signing the result | ||||||
|  | 	// with a hostkey. | ||||||
|  | 	Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error) | ||||||
|  |  | ||||||
|  | 	// Client runs the client-side key agreement. Caller is | ||||||
|  | 	// responsible for verifying the host key signature. | ||||||
|  | 	Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. | ||||||
|  | type dhGroup struct { | ||||||
|  | 	g, p, pMinus1 *big.Int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { | ||||||
|  | 	if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 { | ||||||
|  | 		return nil, errors.New("ssh: DH parameter out of bounds") | ||||||
|  | 	} | ||||||
|  | 	return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { | ||||||
|  | 	hashFunc := crypto.SHA1 | ||||||
|  |  | ||||||
|  | 	var x *big.Int | ||||||
|  | 	for { | ||||||
|  | 		var err error | ||||||
|  | 		if x, err = rand.Int(randSource, group.pMinus1); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		if x.Sign() > 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	X := new(big.Int).Exp(group.g, x, group.p) | ||||||
|  | 	kexDHInit := kexDHInitMsg{ | ||||||
|  | 		X: X, | ||||||
|  | 	} | ||||||
|  | 	if err := c.writePacket(Marshal(&kexDHInit)); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	packet, err := c.readPacket() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var kexDHReply kexDHReplyMsg | ||||||
|  | 	if err = Unmarshal(packet, &kexDHReply); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ki, err := group.diffieHellman(kexDHReply.Y, x) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	h := hashFunc.New() | ||||||
|  | 	magics.write(h) | ||||||
|  | 	writeString(h, kexDHReply.HostKey) | ||||||
|  | 	writeInt(h, X) | ||||||
|  | 	writeInt(h, kexDHReply.Y) | ||||||
|  | 	K := make([]byte, intLength(ki)) | ||||||
|  | 	marshalInt(K, ki) | ||||||
|  | 	h.Write(K) | ||||||
|  |  | ||||||
|  | 	return &kexResult{ | ||||||
|  | 		H:         h.Sum(nil), | ||||||
|  | 		K:         K, | ||||||
|  | 		HostKey:   kexDHReply.HostKey, | ||||||
|  | 		Signature: kexDHReply.Signature, | ||||||
|  | 		Hash:      crypto.SHA1, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { | ||||||
|  | 	hashFunc := crypto.SHA1 | ||||||
|  | 	packet, err := c.readPacket() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	var kexDHInit kexDHInitMsg | ||||||
|  | 	if err = Unmarshal(packet, &kexDHInit); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var y *big.Int | ||||||
|  | 	for { | ||||||
|  | 		if y, err = rand.Int(randSource, group.pMinus1); err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if y.Sign() > 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Y := new(big.Int).Exp(group.g, y, group.p) | ||||||
|  | 	ki, err := group.diffieHellman(kexDHInit.X, y) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	hostKeyBytes := priv.PublicKey().Marshal() | ||||||
|  |  | ||||||
|  | 	h := hashFunc.New() | ||||||
|  | 	magics.write(h) | ||||||
|  | 	writeString(h, hostKeyBytes) | ||||||
|  | 	writeInt(h, kexDHInit.X) | ||||||
|  | 	writeInt(h, Y) | ||||||
|  |  | ||||||
|  | 	K := make([]byte, intLength(ki)) | ||||||
|  | 	marshalInt(K, ki) | ||||||
|  | 	h.Write(K) | ||||||
|  |  | ||||||
|  | 	H := h.Sum(nil) | ||||||
|  |  | ||||||
|  | 	// H is already a hash, but the hostkey signing will apply its | ||||||
|  | 	// own key-specific hash algorithm. | ||||||
|  | 	sig, err := signAndMarshal(priv, randSource, H) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kexDHReply := kexDHReplyMsg{ | ||||||
|  | 		HostKey:   hostKeyBytes, | ||||||
|  | 		Y:         Y, | ||||||
|  | 		Signature: sig, | ||||||
|  | 	} | ||||||
|  | 	packet = Marshal(&kexDHReply) | ||||||
|  |  | ||||||
|  | 	err = c.writePacket(packet) | ||||||
|  | 	return &kexResult{ | ||||||
|  | 		H:         H, | ||||||
|  | 		K:         K, | ||||||
|  | 		HostKey:   hostKeyBytes, | ||||||
|  | 		Signature: sig, | ||||||
|  | 		Hash:      crypto.SHA1, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ecdh performs Elliptic Curve Diffie-Hellman key exchange as | ||||||
|  | // described in RFC 5656, section 4. | ||||||
|  | type ecdh struct { | ||||||
|  | 	curve elliptic.Curve | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { | ||||||
|  | 	ephKey, err := ecdsa.GenerateKey(kex.curve, rand) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kexInit := kexECDHInitMsg{ | ||||||
|  | 		ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	serialized := Marshal(&kexInit) | ||||||
|  | 	if err := c.writePacket(serialized); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	packet, err := c.readPacket() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var reply kexECDHReplyMsg | ||||||
|  | 	if err = Unmarshal(packet, &reply); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// generate shared secret | ||||||
|  | 	secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) | ||||||
|  |  | ||||||
|  | 	h := ecHash(kex.curve).New() | ||||||
|  | 	magics.write(h) | ||||||
|  | 	writeString(h, reply.HostKey) | ||||||
|  | 	writeString(h, kexInit.ClientPubKey) | ||||||
|  | 	writeString(h, reply.EphemeralPubKey) | ||||||
|  | 	K := make([]byte, intLength(secret)) | ||||||
|  | 	marshalInt(K, secret) | ||||||
|  | 	h.Write(K) | ||||||
|  |  | ||||||
|  | 	return &kexResult{ | ||||||
|  | 		H:         h.Sum(nil), | ||||||
|  | 		K:         K, | ||||||
|  | 		HostKey:   reply.HostKey, | ||||||
|  | 		Signature: reply.Signature, | ||||||
|  | 		Hash:      ecHash(kex.curve), | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // unmarshalECKey parses and checks an EC key. | ||||||
|  | func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { | ||||||
|  | 	x, y = elliptic.Unmarshal(curve, pubkey) | ||||||
|  | 	if x == nil { | ||||||
|  | 		return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") | ||||||
|  | 	} | ||||||
|  | 	if !validateECPublicKey(curve, x, y) { | ||||||
|  | 		return nil, nil, errors.New("ssh: public key not on curve") | ||||||
|  | 	} | ||||||
|  | 	return x, y, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // validateECPublicKey checks that the point is a valid public key for | ||||||
|  | // the given curve. See [SEC1], 3.2.2 | ||||||
|  | func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { | ||||||
|  | 	if x.Sign() == 0 && y.Sign() == 0 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if x.Cmp(curve.Params().P) >= 0 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if y.Cmp(curve.Params().P) >= 0 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !curve.IsOnCurve(x, y) { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// We don't check if N * PubKey == 0, since | ||||||
|  | 	// | ||||||
|  | 	// - the NIST curves have cofactor = 1, so this is implicit. | ||||||
|  | 	// (We don't foresee an implementation that supports non NIST | ||||||
|  | 	// curves) | ||||||
|  | 	// | ||||||
|  | 	// - for ephemeral keys, we don't need to worry about small | ||||||
|  | 	// subgroup attacks. | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { | ||||||
|  | 	packet, err := c.readPacket() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var kexECDHInit kexECDHInitMsg | ||||||
|  | 	if err = Unmarshal(packet, &kexECDHInit); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// We could cache this key across multiple users/multiple | ||||||
|  | 	// connection attempts, but the benefit is small. OpenSSH | ||||||
|  | 	// generates a new key for each incoming connection. | ||||||
|  | 	ephKey, err := ecdsa.GenerateKey(kex.curve, rand) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	hostKeyBytes := priv.PublicKey().Marshal() | ||||||
|  |  | ||||||
|  | 	serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) | ||||||
|  |  | ||||||
|  | 	// generate shared secret | ||||||
|  | 	secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) | ||||||
|  |  | ||||||
|  | 	h := ecHash(kex.curve).New() | ||||||
|  | 	magics.write(h) | ||||||
|  | 	writeString(h, hostKeyBytes) | ||||||
|  | 	writeString(h, kexECDHInit.ClientPubKey) | ||||||
|  | 	writeString(h, serializedEphKey) | ||||||
|  |  | ||||||
|  | 	K := make([]byte, intLength(secret)) | ||||||
|  | 	marshalInt(K, secret) | ||||||
|  | 	h.Write(K) | ||||||
|  |  | ||||||
|  | 	H := h.Sum(nil) | ||||||
|  |  | ||||||
|  | 	// H is already a hash, but the hostkey signing will apply its | ||||||
|  | 	// own key-specific hash algorithm. | ||||||
|  | 	sig, err := signAndMarshal(priv, rand, H) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	reply := kexECDHReplyMsg{ | ||||||
|  | 		EphemeralPubKey: serializedEphKey, | ||||||
|  | 		HostKey:         hostKeyBytes, | ||||||
|  | 		Signature:       sig, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	serialized := Marshal(&reply) | ||||||
|  | 	if err := c.writePacket(serialized); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &kexResult{ | ||||||
|  | 		H:         H, | ||||||
|  | 		K:         K, | ||||||
|  | 		HostKey:   reply.HostKey, | ||||||
|  | 		Signature: sig, | ||||||
|  | 		Hash:      ecHash(kex.curve), | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var kexAlgoMap = map[string]kexAlgorithm{} | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	// This is the group called diffie-hellman-group1-sha1 in RFC | ||||||
|  | 	// 4253 and Oakley Group 2 in RFC 2409. | ||||||
|  | 	p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) | ||||||
|  | 	kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ | ||||||
|  | 		g:       new(big.Int).SetInt64(2), | ||||||
|  | 		p:       p, | ||||||
|  | 		pMinus1: new(big.Int).Sub(p, bigOne), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// This is the group called diffie-hellman-group14-sha1 in RFC | ||||||
|  | 	// 4253 and Oakley Group 14 in RFC 3526. | ||||||
|  | 	p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) | ||||||
|  |  | ||||||
|  | 	kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ | ||||||
|  | 		g:       new(big.Int).SetInt64(2), | ||||||
|  | 		p:       p, | ||||||
|  | 		pMinus1: new(big.Int).Sub(p, bigOne), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} | ||||||
|  | 	kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} | ||||||
|  | 	kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} | ||||||
|  | 	kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // curve25519sha256 implements the curve25519-sha256@libssh.org key | ||||||
|  | // agreement protocol, as described in | ||||||
|  | // https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt | ||||||
|  | type curve25519sha256 struct{} | ||||||
|  |  | ||||||
|  | type curve25519KeyPair struct { | ||||||
|  | 	priv [32]byte | ||||||
|  | 	pub  [32]byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (kp *curve25519KeyPair) generate(rand io.Reader) error { | ||||||
|  | 	if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	curve25519.ScalarBaseMult(&kp.pub, &kp.priv) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // curve25519Zeros is just an array of 32 zero bytes so that we have something | ||||||
|  | // convenient to compare against in order to reject curve25519 points with the | ||||||
|  | // wrong order. | ||||||
|  | var curve25519Zeros [32]byte | ||||||
|  |  | ||||||
|  | func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { | ||||||
|  | 	var kp curve25519KeyPair | ||||||
|  | 	if err := kp.generate(rand); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	packet, err := c.readPacket() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var reply kexECDHReplyMsg | ||||||
|  | 	if err = Unmarshal(packet, &reply); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if len(reply.EphemeralPubKey) != 32 { | ||||||
|  | 		return nil, errors.New("ssh: peer's curve25519 public value has wrong length") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var servPub, secret [32]byte | ||||||
|  | 	copy(servPub[:], reply.EphemeralPubKey) | ||||||
|  | 	curve25519.ScalarMult(&secret, &kp.priv, &servPub) | ||||||
|  | 	if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { | ||||||
|  | 		return nil, errors.New("ssh: peer's curve25519 public value has wrong order") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	h := crypto.SHA256.New() | ||||||
|  | 	magics.write(h) | ||||||
|  | 	writeString(h, reply.HostKey) | ||||||
|  | 	writeString(h, kp.pub[:]) | ||||||
|  | 	writeString(h, reply.EphemeralPubKey) | ||||||
|  |  | ||||||
|  | 	ki := new(big.Int).SetBytes(secret[:]) | ||||||
|  | 	K := make([]byte, intLength(ki)) | ||||||
|  | 	marshalInt(K, ki) | ||||||
|  | 	h.Write(K) | ||||||
|  |  | ||||||
|  | 	return &kexResult{ | ||||||
|  | 		H:         h.Sum(nil), | ||||||
|  | 		K:         K, | ||||||
|  | 		HostKey:   reply.HostKey, | ||||||
|  | 		Signature: reply.Signature, | ||||||
|  | 		Hash:      crypto.SHA256, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { | ||||||
|  | 	packet, err := c.readPacket() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	var kexInit kexECDHInitMsg | ||||||
|  | 	if err = Unmarshal(packet, &kexInit); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(kexInit.ClientPubKey) != 32 { | ||||||
|  | 		return nil, errors.New("ssh: peer's curve25519 public value has wrong length") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var kp curve25519KeyPair | ||||||
|  | 	if err := kp.generate(rand); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var clientPub, secret [32]byte | ||||||
|  | 	copy(clientPub[:], kexInit.ClientPubKey) | ||||||
|  | 	curve25519.ScalarMult(&secret, &kp.priv, &clientPub) | ||||||
|  | 	if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { | ||||||
|  | 		return nil, errors.New("ssh: peer's curve25519 public value has wrong order") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	hostKeyBytes := priv.PublicKey().Marshal() | ||||||
|  |  | ||||||
|  | 	h := crypto.SHA256.New() | ||||||
|  | 	magics.write(h) | ||||||
|  | 	writeString(h, hostKeyBytes) | ||||||
|  | 	writeString(h, kexInit.ClientPubKey) | ||||||
|  | 	writeString(h, kp.pub[:]) | ||||||
|  |  | ||||||
|  | 	ki := new(big.Int).SetBytes(secret[:]) | ||||||
|  | 	K := make([]byte, intLength(ki)) | ||||||
|  | 	marshalInt(K, ki) | ||||||
|  | 	h.Write(K) | ||||||
|  |  | ||||||
|  | 	H := h.Sum(nil) | ||||||
|  |  | ||||||
|  | 	sig, err := signAndMarshal(priv, rand, H) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	reply := kexECDHReplyMsg{ | ||||||
|  | 		EphemeralPubKey: kp.pub[:], | ||||||
|  | 		HostKey:         hostKeyBytes, | ||||||
|  | 		Signature:       sig, | ||||||
|  | 	} | ||||||
|  | 	if err := c.writePacket(Marshal(&reply)); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &kexResult{ | ||||||
|  | 		H:         H, | ||||||
|  | 		K:         K, | ||||||
|  | 		HostKey:   hostKeyBytes, | ||||||
|  | 		Signature: sig, | ||||||
|  | 		Hash:      crypto.SHA256, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
							
								
								
									
										1031
									
								
								vendor/golang.org/x/crypto/ssh/keys.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1031
									
								
								vendor/golang.org/x/crypto/ssh/keys.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										546
									
								
								vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										546
									
								
								vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,546 @@ | |||||||
|  | // Copyright 2017 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 knownhosts implements a parser for the OpenSSH | ||||||
|  | // known_hosts host key database. | ||||||
|  | package knownhosts | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"bytes" | ||||||
|  | 	"crypto/hmac" | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"crypto/sha1" | ||||||
|  | 	"encoding/base64" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"net" | ||||||
|  | 	"os" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/crypto/ssh" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // See the sshd manpage | ||||||
|  | // (http://man.openbsd.org/sshd#SSH_KNOWN_HOSTS_FILE_FORMAT) for | ||||||
|  | // background. | ||||||
|  |  | ||||||
|  | type addr struct{ host, port string } | ||||||
|  |  | ||||||
|  | func (a *addr) String() string { | ||||||
|  | 	h := a.host | ||||||
|  | 	if strings.Contains(h, ":") { | ||||||
|  | 		h = "[" + h + "]" | ||||||
|  | 	} | ||||||
|  | 	return h + ":" + a.port | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type matcher interface { | ||||||
|  | 	match([]addr) bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type hostPattern struct { | ||||||
|  | 	negate bool | ||||||
|  | 	addr   addr | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *hostPattern) String() string { | ||||||
|  | 	n := "" | ||||||
|  | 	if p.negate { | ||||||
|  | 		n = "!" | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return n + p.addr.String() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type hostPatterns []hostPattern | ||||||
|  |  | ||||||
|  | func (ps hostPatterns) match(addrs []addr) bool { | ||||||
|  | 	matched := false | ||||||
|  | 	for _, p := range ps { | ||||||
|  | 		for _, a := range addrs { | ||||||
|  | 			m := p.match(a) | ||||||
|  | 			if !m { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			if p.negate { | ||||||
|  | 				return false | ||||||
|  | 			} | ||||||
|  | 			matched = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return matched | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // See | ||||||
|  | // https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/addrmatch.c | ||||||
|  | // The matching of * has no regard for separators, unlike filesystem globs | ||||||
|  | func wildcardMatch(pat []byte, str []byte) bool { | ||||||
|  | 	for { | ||||||
|  | 		if len(pat) == 0 { | ||||||
|  | 			return len(str) == 0 | ||||||
|  | 		} | ||||||
|  | 		if len(str) == 0 { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if pat[0] == '*' { | ||||||
|  | 			if len(pat) == 1 { | ||||||
|  | 				return true | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			for j := range str { | ||||||
|  | 				if wildcardMatch(pat[1:], str[j:]) { | ||||||
|  | 					return true | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if pat[0] == '?' || pat[0] == str[0] { | ||||||
|  | 			pat = pat[1:] | ||||||
|  | 			str = str[1:] | ||||||
|  | 		} else { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *hostPattern) match(a addr) bool { | ||||||
|  | 	return wildcardMatch([]byte(p.addr.host), []byte(a.host)) && p.addr.port == a.port | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type keyDBLine struct { | ||||||
|  | 	cert     bool | ||||||
|  | 	matcher  matcher | ||||||
|  | 	knownKey KnownKey | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func serialize(k ssh.PublicKey) string { | ||||||
|  | 	return k.Type() + " " + base64.StdEncoding.EncodeToString(k.Marshal()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *keyDBLine) match(addrs []addr) bool { | ||||||
|  | 	return l.matcher.match(addrs) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type hostKeyDB struct { | ||||||
|  | 	// Serialized version of revoked keys | ||||||
|  | 	revoked map[string]*KnownKey | ||||||
|  | 	lines   []keyDBLine | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newHostKeyDB() *hostKeyDB { | ||||||
|  | 	db := &hostKeyDB{ | ||||||
|  | 		revoked: make(map[string]*KnownKey), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return db | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func keyEq(a, b ssh.PublicKey) bool { | ||||||
|  | 	return bytes.Equal(a.Marshal(), b.Marshal()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsAuthorityForHost can be used as a callback in ssh.CertChecker | ||||||
|  | func (db *hostKeyDB) IsHostAuthority(remote ssh.PublicKey, address string) bool { | ||||||
|  | 	h, p, err := net.SplitHostPort(address) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	a := addr{host: h, port: p} | ||||||
|  |  | ||||||
|  | 	for _, l := range db.lines { | ||||||
|  | 		if l.cert && keyEq(l.knownKey.Key, remote) && l.match([]addr{a}) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsRevoked can be used as a callback in ssh.CertChecker | ||||||
|  | func (db *hostKeyDB) IsRevoked(key *ssh.Certificate) bool { | ||||||
|  | 	_, ok := db.revoked[string(key.Marshal())] | ||||||
|  | 	return ok | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const markerCert = "@cert-authority" | ||||||
|  | const markerRevoked = "@revoked" | ||||||
|  |  | ||||||
|  | func nextWord(line []byte) (string, []byte) { | ||||||
|  | 	i := bytes.IndexAny(line, "\t ") | ||||||
|  | 	if i == -1 { | ||||||
|  | 		return string(line), nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return string(line[:i]), bytes.TrimSpace(line[i:]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseLine(line []byte) (marker, host string, key ssh.PublicKey, err error) { | ||||||
|  | 	if w, next := nextWord(line); w == markerCert || w == markerRevoked { | ||||||
|  | 		marker = w | ||||||
|  | 		line = next | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	host, line = nextWord(line) | ||||||
|  | 	if len(line) == 0 { | ||||||
|  | 		return "", "", nil, errors.New("knownhosts: missing host pattern") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// ignore the keytype as it's in the key blob anyway. | ||||||
|  | 	_, line = nextWord(line) | ||||||
|  | 	if len(line) == 0 { | ||||||
|  | 		return "", "", nil, errors.New("knownhosts: missing key type pattern") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	keyBlob, _ := nextWord(line) | ||||||
|  |  | ||||||
|  | 	keyBytes, err := base64.StdEncoding.DecodeString(keyBlob) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", "", nil, err | ||||||
|  | 	} | ||||||
|  | 	key, err = ssh.ParsePublicKey(keyBytes) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", "", nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return marker, host, key, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (db *hostKeyDB) parseLine(line []byte, filename string, linenum int) error { | ||||||
|  | 	marker, pattern, key, err := parseLine(line) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if marker == markerRevoked { | ||||||
|  | 		db.revoked[string(key.Marshal())] = &KnownKey{ | ||||||
|  | 			Key:      key, | ||||||
|  | 			Filename: filename, | ||||||
|  | 			Line:     linenum, | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	entry := keyDBLine{ | ||||||
|  | 		cert: marker == markerCert, | ||||||
|  | 		knownKey: KnownKey{ | ||||||
|  | 			Filename: filename, | ||||||
|  | 			Line:     linenum, | ||||||
|  | 			Key:      key, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if pattern[0] == '|' { | ||||||
|  | 		entry.matcher, err = newHashedHost(pattern) | ||||||
|  | 	} else { | ||||||
|  | 		entry.matcher, err = newHostnameMatcher(pattern) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	db.lines = append(db.lines, entry) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newHostnameMatcher(pattern string) (matcher, error) { | ||||||
|  | 	var hps hostPatterns | ||||||
|  | 	for _, p := range strings.Split(pattern, ",") { | ||||||
|  | 		if len(p) == 0 { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var a addr | ||||||
|  | 		var negate bool | ||||||
|  | 		if p[0] == '!' { | ||||||
|  | 			negate = true | ||||||
|  | 			p = p[1:] | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if len(p) == 0 { | ||||||
|  | 			return nil, errors.New("knownhosts: negation without following hostname") | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var err error | ||||||
|  | 		if p[0] == '[' { | ||||||
|  | 			a.host, a.port, err = net.SplitHostPort(p) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			a.host, a.port, err = net.SplitHostPort(p) | ||||||
|  | 			if err != nil { | ||||||
|  | 				a.host = p | ||||||
|  | 				a.port = "22" | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		hps = append(hps, hostPattern{ | ||||||
|  | 			negate: negate, | ||||||
|  | 			addr:   a, | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 	return hps, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // KnownKey represents a key declared in a known_hosts file. | ||||||
|  | type KnownKey struct { | ||||||
|  | 	Key      ssh.PublicKey | ||||||
|  | 	Filename string | ||||||
|  | 	Line     int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (k *KnownKey) String() string { | ||||||
|  | 	return fmt.Sprintf("%s:%d: %s", k.Filename, k.Line, serialize(k.Key)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // KeyError is returned if we did not find the key in the host key | ||||||
|  | // database, or there was a mismatch.  Typically, in batch | ||||||
|  | // applications, this should be interpreted as failure. Interactive | ||||||
|  | // applications can offer an interactive prompt to the user. | ||||||
|  | type KeyError struct { | ||||||
|  | 	// Want holds the accepted host keys. For each key algorithm, | ||||||
|  | 	// there can be one hostkey.  If Want is empty, the host is | ||||||
|  | 	// unknown. If Want is non-empty, there was a mismatch, which | ||||||
|  | 	// can signify a MITM attack. | ||||||
|  | 	Want []KnownKey | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (u *KeyError) Error() string { | ||||||
|  | 	if len(u.Want) == 0 { | ||||||
|  | 		return "knownhosts: key is unknown" | ||||||
|  | 	} | ||||||
|  | 	return "knownhosts: key mismatch" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RevokedError is returned if we found a key that was revoked. | ||||||
|  | type RevokedError struct { | ||||||
|  | 	Revoked KnownKey | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *RevokedError) Error() string { | ||||||
|  | 	return "knownhosts: key is revoked" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // check checks a key against the host database. This should not be | ||||||
|  | // used for verifying certificates. | ||||||
|  | func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.PublicKey) error { | ||||||
|  | 	if revoked := db.revoked[string(remoteKey.Marshal())]; revoked != nil { | ||||||
|  | 		return &RevokedError{Revoked: *revoked} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	host, port, err := net.SplitHostPort(remote.String()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", remote, err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	addrs := []addr{ | ||||||
|  | 		{host, port}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if address != "" { | ||||||
|  | 		host, port, err := net.SplitHostPort(address) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", address, err) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		addrs = append(addrs, addr{host, port}) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return db.checkAddrs(addrs, remoteKey) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // checkAddrs checks if we can find the given public key for any of | ||||||
|  | // the given addresses.  If we only find an entry for the IP address, | ||||||
|  | // or only the hostname, then this still succeeds. | ||||||
|  | func (db *hostKeyDB) checkAddrs(addrs []addr, remoteKey ssh.PublicKey) error { | ||||||
|  | 	// TODO(hanwen): are these the right semantics? What if there | ||||||
|  | 	// is just a key for the IP address, but not for the | ||||||
|  | 	// hostname? | ||||||
|  |  | ||||||
|  | 	// Algorithm => key. | ||||||
|  | 	knownKeys := map[string]KnownKey{} | ||||||
|  | 	for _, l := range db.lines { | ||||||
|  | 		if l.match(addrs) { | ||||||
|  | 			typ := l.knownKey.Key.Type() | ||||||
|  | 			if _, ok := knownKeys[typ]; !ok { | ||||||
|  | 				knownKeys[typ] = l.knownKey | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	keyErr := &KeyError{} | ||||||
|  | 	for _, v := range knownKeys { | ||||||
|  | 		keyErr.Want = append(keyErr.Want, v) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Unknown remote host. | ||||||
|  | 	if len(knownKeys) == 0 { | ||||||
|  | 		return keyErr | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// If the remote host starts using a different, unknown key type, we | ||||||
|  | 	// also interpret that as a mismatch. | ||||||
|  | 	if known, ok := knownKeys[remoteKey.Type()]; !ok || !keyEq(known.Key, remoteKey) { | ||||||
|  | 		return keyErr | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // The Read function parses file contents. | ||||||
|  | func (db *hostKeyDB) Read(r io.Reader, filename string) error { | ||||||
|  | 	scanner := bufio.NewScanner(r) | ||||||
|  |  | ||||||
|  | 	lineNum := 0 | ||||||
|  | 	for scanner.Scan() { | ||||||
|  | 		lineNum++ | ||||||
|  | 		line := scanner.Bytes() | ||||||
|  | 		line = bytes.TrimSpace(line) | ||||||
|  | 		if len(line) == 0 || line[0] == '#' { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if err := db.parseLine(line, filename, lineNum); err != nil { | ||||||
|  | 			return fmt.Errorf("knownhosts: %s:%d: %v", filename, lineNum, err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return scanner.Err() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // New creates a host key callback from the given OpenSSH host key | ||||||
|  | // files. The returned callback is for use in | ||||||
|  | // ssh.ClientConfig.HostKeyCallback. Hashed hostnames are not supported. | ||||||
|  | func New(files ...string) (ssh.HostKeyCallback, error) { | ||||||
|  | 	db := newHostKeyDB() | ||||||
|  | 	for _, fn := range files { | ||||||
|  | 		f, err := os.Open(fn) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		defer f.Close() | ||||||
|  | 		if err := db.Read(f, fn); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var certChecker ssh.CertChecker | ||||||
|  | 	certChecker.IsHostAuthority = db.IsHostAuthority | ||||||
|  | 	certChecker.IsRevoked = db.IsRevoked | ||||||
|  | 	certChecker.HostKeyFallback = db.check | ||||||
|  |  | ||||||
|  | 	return certChecker.CheckHostKey, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Normalize normalizes an address into the form used in known_hosts | ||||||
|  | func Normalize(address string) string { | ||||||
|  | 	host, port, err := net.SplitHostPort(address) | ||||||
|  | 	if err != nil { | ||||||
|  | 		host = address | ||||||
|  | 		port = "22" | ||||||
|  | 	} | ||||||
|  | 	entry := host | ||||||
|  | 	if port != "22" { | ||||||
|  | 		entry = "[" + entry + "]:" + port | ||||||
|  | 	} else if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") { | ||||||
|  | 		entry = "[" + entry + "]" | ||||||
|  | 	} | ||||||
|  | 	return entry | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Line returns a line to add append to the known_hosts files. | ||||||
|  | func Line(addresses []string, key ssh.PublicKey) string { | ||||||
|  | 	var trimmed []string | ||||||
|  | 	for _, a := range addresses { | ||||||
|  | 		trimmed = append(trimmed, Normalize(a)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return strings.Join(trimmed, ",") + " " + serialize(key) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // HashHostname hashes the given hostname. The hostname is not | ||||||
|  | // normalized before hashing. | ||||||
|  | func HashHostname(hostname string) string { | ||||||
|  | 	// TODO(hanwen): check if we can safely normalize this always. | ||||||
|  | 	salt := make([]byte, sha1.Size) | ||||||
|  |  | ||||||
|  | 	_, err := rand.Read(salt) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(fmt.Sprintf("crypto/rand failure %v", err)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	hash := hashHost(hostname, salt) | ||||||
|  | 	return encodeHash(sha1HashType, salt, hash) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func decodeHash(encoded string) (hashType string, salt, hash []byte, err error) { | ||||||
|  | 	if len(encoded) == 0 || encoded[0] != '|' { | ||||||
|  | 		err = errors.New("knownhosts: hashed host must start with '|'") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	components := strings.Split(encoded, "|") | ||||||
|  | 	if len(components) != 4 { | ||||||
|  | 		err = fmt.Errorf("knownhosts: got %d components, want 3", len(components)) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	hashType = components[1] | ||||||
|  | 	if salt, err = base64.StdEncoding.DecodeString(components[2]); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if hash, err = base64.StdEncoding.DecodeString(components[3]); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func encodeHash(typ string, salt []byte, hash []byte) string { | ||||||
|  | 	return strings.Join([]string{"", | ||||||
|  | 		typ, | ||||||
|  | 		base64.StdEncoding.EncodeToString(salt), | ||||||
|  | 		base64.StdEncoding.EncodeToString(hash), | ||||||
|  | 	}, "|") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // See https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/hostfile.c#120 | ||||||
|  | func hashHost(hostname string, salt []byte) []byte { | ||||||
|  | 	mac := hmac.New(sha1.New, salt) | ||||||
|  | 	mac.Write([]byte(hostname)) | ||||||
|  | 	return mac.Sum(nil) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type hashedHost struct { | ||||||
|  | 	salt []byte | ||||||
|  | 	hash []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const sha1HashType = "1" | ||||||
|  |  | ||||||
|  | func newHashedHost(encoded string) (*hashedHost, error) { | ||||||
|  | 	typ, salt, hash, err := decodeHash(encoded) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// The type field seems for future algorithm agility, but it's | ||||||
|  | 	// actually hardcoded in openssh currently, see | ||||||
|  | 	// https://android.googlesource.com/platform/external/openssh/+/ab28f5495c85297e7a597c1ba62e996416da7c7e/hostfile.c#120 | ||||||
|  | 	if typ != sha1HashType { | ||||||
|  | 		return nil, fmt.Errorf("knownhosts: got hash type %s, must be '1'", typ) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &hashedHost{salt: salt, hash: hash}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (h *hashedHost) match(addrs []addr) bool { | ||||||
|  | 	for _, a := range addrs { | ||||||
|  | 		if bytes.Equal(hashHost(Normalize(a.String()), h.salt), h.hash) { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
							
								
								
									
										61
									
								
								vendor/golang.org/x/crypto/ssh/mac.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								vendor/golang.org/x/crypto/ssh/mac.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | |||||||
|  | // Copyright 2012 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 | ||||||
|  |  | ||||||
|  | // Message authentication support | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"crypto/hmac" | ||||||
|  | 	"crypto/sha1" | ||||||
|  | 	"crypto/sha256" | ||||||
|  | 	"hash" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type macMode struct { | ||||||
|  | 	keySize int | ||||||
|  | 	etm     bool | ||||||
|  | 	new     func(key []byte) hash.Hash | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // truncatingMAC wraps around a hash.Hash and truncates the output digest to | ||||||
|  | // a given size. | ||||||
|  | type truncatingMAC struct { | ||||||
|  | 	length int | ||||||
|  | 	hmac   hash.Hash | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t truncatingMAC) Write(data []byte) (int, error) { | ||||||
|  | 	return t.hmac.Write(data) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t truncatingMAC) Sum(in []byte) []byte { | ||||||
|  | 	out := t.hmac.Sum(in) | ||||||
|  | 	return out[:len(in)+t.length] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t truncatingMAC) Reset() { | ||||||
|  | 	t.hmac.Reset() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t truncatingMAC) Size() int { | ||||||
|  | 	return t.length | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } | ||||||
|  |  | ||||||
|  | var macModes = map[string]*macMode{ | ||||||
|  | 	"hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash { | ||||||
|  | 		return hmac.New(sha256.New, key) | ||||||
|  | 	}}, | ||||||
|  | 	"hmac-sha2-256": {32, false, func(key []byte) hash.Hash { | ||||||
|  | 		return hmac.New(sha256.New, key) | ||||||
|  | 	}}, | ||||||
|  | 	"hmac-sha1": {20, false, func(key []byte) hash.Hash { | ||||||
|  | 		return hmac.New(sha1.New, key) | ||||||
|  | 	}}, | ||||||
|  | 	"hmac-sha1-96": {20, false, func(key []byte) hash.Hash { | ||||||
|  | 		return truncatingMAC{12, hmac.New(sha1.New, key)} | ||||||
|  | 	}}, | ||||||
|  | } | ||||||
							
								
								
									
										766
									
								
								vendor/golang.org/x/crypto/ssh/messages.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										766
									
								
								vendor/golang.org/x/crypto/ssh/messages.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,766 @@ | |||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | // Diffie-Helman | ||||||
|  | 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 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"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 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 { | ||||||
|  | 	User               string `sshtype:"60"` | ||||||
|  | 	Instruction        string | ||||||
|  | 	DeprecatedLanguage string | ||||||
|  | 	NumPrompts         uint32 | ||||||
|  | 	Prompts            []byte `ssh:"rest"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 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 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 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) | ||||||
|  | 	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) | ||||||
|  | 	default: | ||||||
|  | 		return nil, unexpectedMessageError(0, packet[0]) | ||||||
|  | 	} | ||||||
|  | 	if err := Unmarshal(packet, msg); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return msg, nil | ||||||
|  | } | ||||||
							
								
								
									
										330
									
								
								vendor/golang.org/x/crypto/ssh/mux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								vendor/golang.org/x/crypto/ssh/mux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,330 @@ | |||||||
|  | // Copyright 2013 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 ( | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"log" | ||||||
|  | 	"sync" | ||||||
|  | 	"sync/atomic" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // debugMux, if set, causes messages in the connection protocol to be | ||||||
|  | // logged. | ||||||
|  | const debugMux = false | ||||||
|  |  | ||||||
|  | // chanList is a thread safe channel list. | ||||||
|  | type chanList struct { | ||||||
|  | 	// protects concurrent access to chans | ||||||
|  | 	sync.Mutex | ||||||
|  |  | ||||||
|  | 	// chans are indexed by the local id of the channel, which the | ||||||
|  | 	// other side should send in the PeersId field. | ||||||
|  | 	chans []*channel | ||||||
|  |  | ||||||
|  | 	// This is a debugging aid: it offsets all IDs by this | ||||||
|  | 	// amount. This helps distinguish otherwise identical | ||||||
|  | 	// server/client muxes | ||||||
|  | 	offset uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Assigns a channel ID to the given channel. | ||||||
|  | func (c *chanList) add(ch *channel) uint32 { | ||||||
|  | 	c.Lock() | ||||||
|  | 	defer c.Unlock() | ||||||
|  | 	for i := range c.chans { | ||||||
|  | 		if c.chans[i] == nil { | ||||||
|  | 			c.chans[i] = ch | ||||||
|  | 			return uint32(i) + c.offset | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	c.chans = append(c.chans, ch) | ||||||
|  | 	return uint32(len(c.chans)-1) + c.offset | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // getChan returns the channel for the given ID. | ||||||
|  | func (c *chanList) getChan(id uint32) *channel { | ||||||
|  | 	id -= c.offset | ||||||
|  |  | ||||||
|  | 	c.Lock() | ||||||
|  | 	defer c.Unlock() | ||||||
|  | 	if id < uint32(len(c.chans)) { | ||||||
|  | 		return c.chans[id] | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *chanList) remove(id uint32) { | ||||||
|  | 	id -= c.offset | ||||||
|  | 	c.Lock() | ||||||
|  | 	if id < uint32(len(c.chans)) { | ||||||
|  | 		c.chans[id] = nil | ||||||
|  | 	} | ||||||
|  | 	c.Unlock() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // dropAll forgets all channels it knows, returning them in a slice. | ||||||
|  | func (c *chanList) dropAll() []*channel { | ||||||
|  | 	c.Lock() | ||||||
|  | 	defer c.Unlock() | ||||||
|  | 	var r []*channel | ||||||
|  |  | ||||||
|  | 	for _, ch := range c.chans { | ||||||
|  | 		if ch == nil { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		r = append(r, ch) | ||||||
|  | 	} | ||||||
|  | 	c.chans = nil | ||||||
|  | 	return r | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // mux represents the state for the SSH connection protocol, which | ||||||
|  | // multiplexes many channels onto a single packet transport. | ||||||
|  | type mux struct { | ||||||
|  | 	conn     packetConn | ||||||
|  | 	chanList chanList | ||||||
|  |  | ||||||
|  | 	incomingChannels chan NewChannel | ||||||
|  |  | ||||||
|  | 	globalSentMu     sync.Mutex | ||||||
|  | 	globalResponses  chan interface{} | ||||||
|  | 	incomingRequests chan *Request | ||||||
|  |  | ||||||
|  | 	errCond *sync.Cond | ||||||
|  | 	err     error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // When debugging, each new chanList instantiation has a different | ||||||
|  | // offset. | ||||||
|  | var globalOff uint32 | ||||||
|  |  | ||||||
|  | func (m *mux) Wait() error { | ||||||
|  | 	m.errCond.L.Lock() | ||||||
|  | 	defer m.errCond.L.Unlock() | ||||||
|  | 	for m.err == nil { | ||||||
|  | 		m.errCond.Wait() | ||||||
|  | 	} | ||||||
|  | 	return m.err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // newMux returns a mux that runs over the given connection. | ||||||
|  | func newMux(p packetConn) *mux { | ||||||
|  | 	m := &mux{ | ||||||
|  | 		conn:             p, | ||||||
|  | 		incomingChannels: make(chan NewChannel, chanSize), | ||||||
|  | 		globalResponses:  make(chan interface{}, 1), | ||||||
|  | 		incomingRequests: make(chan *Request, chanSize), | ||||||
|  | 		errCond:          newCond(), | ||||||
|  | 	} | ||||||
|  | 	if debugMux { | ||||||
|  | 		m.chanList.offset = atomic.AddUint32(&globalOff, 1) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	go m.loop() | ||||||
|  | 	return m | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *mux) sendMessage(msg interface{}) error { | ||||||
|  | 	p := Marshal(msg) | ||||||
|  | 	if debugMux { | ||||||
|  | 		log.Printf("send global(%d): %#v", m.chanList.offset, msg) | ||||||
|  | 	} | ||||||
|  | 	return m.conn.writePacket(p) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) { | ||||||
|  | 	if wantReply { | ||||||
|  | 		m.globalSentMu.Lock() | ||||||
|  | 		defer m.globalSentMu.Unlock() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := m.sendMessage(globalRequestMsg{ | ||||||
|  | 		Type:      name, | ||||||
|  | 		WantReply: wantReply, | ||||||
|  | 		Data:      payload, | ||||||
|  | 	}); err != nil { | ||||||
|  | 		return false, nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !wantReply { | ||||||
|  | 		return false, nil, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	msg, ok := <-m.globalResponses | ||||||
|  | 	if !ok { | ||||||
|  | 		return false, nil, io.EOF | ||||||
|  | 	} | ||||||
|  | 	switch msg := msg.(type) { | ||||||
|  | 	case *globalRequestFailureMsg: | ||||||
|  | 		return false, msg.Data, nil | ||||||
|  | 	case *globalRequestSuccessMsg: | ||||||
|  | 		return true, msg.Data, nil | ||||||
|  | 	default: | ||||||
|  | 		return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ackRequest must be called after processing a global request that | ||||||
|  | // has WantReply set. | ||||||
|  | func (m *mux) ackRequest(ok bool, data []byte) error { | ||||||
|  | 	if ok { | ||||||
|  | 		return m.sendMessage(globalRequestSuccessMsg{Data: data}) | ||||||
|  | 	} | ||||||
|  | 	return m.sendMessage(globalRequestFailureMsg{Data: data}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *mux) Close() error { | ||||||
|  | 	return m.conn.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // loop runs the connection machine. It will process packets until an | ||||||
|  | // error is encountered. To synchronize on loop exit, use mux.Wait. | ||||||
|  | func (m *mux) loop() { | ||||||
|  | 	var err error | ||||||
|  | 	for err == nil { | ||||||
|  | 		err = m.onePacket() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, ch := range m.chanList.dropAll() { | ||||||
|  | 		ch.close() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	close(m.incomingChannels) | ||||||
|  | 	close(m.incomingRequests) | ||||||
|  | 	close(m.globalResponses) | ||||||
|  |  | ||||||
|  | 	m.conn.Close() | ||||||
|  |  | ||||||
|  | 	m.errCond.L.Lock() | ||||||
|  | 	m.err = err | ||||||
|  | 	m.errCond.Broadcast() | ||||||
|  | 	m.errCond.L.Unlock() | ||||||
|  |  | ||||||
|  | 	if debugMux { | ||||||
|  | 		log.Println("loop exit", err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // onePacket reads and processes one packet. | ||||||
|  | func (m *mux) onePacket() error { | ||||||
|  | 	packet, err := m.conn.readPacket() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if debugMux { | ||||||
|  | 		if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData { | ||||||
|  | 			log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet)) | ||||||
|  | 		} else { | ||||||
|  | 			p, _ := decode(packet) | ||||||
|  | 			log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch packet[0] { | ||||||
|  | 	case msgChannelOpen: | ||||||
|  | 		return m.handleChannelOpen(packet) | ||||||
|  | 	case msgGlobalRequest, msgRequestSuccess, msgRequestFailure: | ||||||
|  | 		return m.handleGlobalPacket(packet) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// assume a channel packet. | ||||||
|  | 	if len(packet) < 5 { | ||||||
|  | 		return parseError(packet[0]) | ||||||
|  | 	} | ||||||
|  | 	id := binary.BigEndian.Uint32(packet[1:]) | ||||||
|  | 	ch := m.chanList.getChan(id) | ||||||
|  | 	if ch == nil { | ||||||
|  | 		return fmt.Errorf("ssh: invalid channel %d", id) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ch.handlePacket(packet) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *mux) handleGlobalPacket(packet []byte) error { | ||||||
|  | 	msg, err := decode(packet) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch msg := msg.(type) { | ||||||
|  | 	case *globalRequestMsg: | ||||||
|  | 		m.incomingRequests <- &Request{ | ||||||
|  | 			Type:      msg.Type, | ||||||
|  | 			WantReply: msg.WantReply, | ||||||
|  | 			Payload:   msg.Data, | ||||||
|  | 			mux:       m, | ||||||
|  | 		} | ||||||
|  | 	case *globalRequestSuccessMsg, *globalRequestFailureMsg: | ||||||
|  | 		m.globalResponses <- msg | ||||||
|  | 	default: | ||||||
|  | 		panic(fmt.Sprintf("not a global message %#v", msg)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // handleChannelOpen schedules a channel to be Accept()ed. | ||||||
|  | func (m *mux) handleChannelOpen(packet []byte) error { | ||||||
|  | 	var msg channelOpenMsg | ||||||
|  | 	if err := Unmarshal(packet, &msg); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { | ||||||
|  | 		failMsg := channelOpenFailureMsg{ | ||||||
|  | 			PeersID:  msg.PeersID, | ||||||
|  | 			Reason:   ConnectionFailed, | ||||||
|  | 			Message:  "invalid request", | ||||||
|  | 			Language: "en_US.UTF-8", | ||||||
|  | 		} | ||||||
|  | 		return m.sendMessage(failMsg) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData) | ||||||
|  | 	c.remoteId = msg.PeersID | ||||||
|  | 	c.maxRemotePayload = msg.MaxPacketSize | ||||||
|  | 	c.remoteWin.add(msg.PeersWindow) | ||||||
|  | 	m.incomingChannels <- c | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) { | ||||||
|  | 	ch, err := m.openChannel(chanType, extra) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ch, ch.incomingRequests, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) { | ||||||
|  | 	ch := m.newChannel(chanType, channelOutbound, extra) | ||||||
|  |  | ||||||
|  | 	ch.maxIncomingPayload = channelMaxPacket | ||||||
|  |  | ||||||
|  | 	open := channelOpenMsg{ | ||||||
|  | 		ChanType:         chanType, | ||||||
|  | 		PeersWindow:      ch.myWindow, | ||||||
|  | 		MaxPacketSize:    ch.maxIncomingPayload, | ||||||
|  | 		TypeSpecificData: extra, | ||||||
|  | 		PeersID:          ch.localId, | ||||||
|  | 	} | ||||||
|  | 	if err := m.sendMessage(open); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch msg := (<-ch.msg).(type) { | ||||||
|  | 	case *channelOpenConfirmMsg: | ||||||
|  | 		return ch, nil | ||||||
|  | 	case *channelOpenFailureMsg: | ||||||
|  | 		return nil, &OpenChannelError{msg.Reason, msg.Message} | ||||||
|  | 	default: | ||||||
|  | 		return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										582
									
								
								vendor/golang.org/x/crypto/ssh/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										582
									
								
								vendor/golang.org/x/crypto/ssh/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,582 @@ | |||||||
|  | // 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" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"net" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // The Permissions type holds fine-grained permissions that are | ||||||
|  | // specific to a user or a specific authentication method for a user. | ||||||
|  | // The Permissions value for a successful authentication attempt is | ||||||
|  | // available in ServerConn, so it can be used to pass information from | ||||||
|  | // the user-authentication phase to the application layer. | ||||||
|  | type Permissions struct { | ||||||
|  | 	// CriticalOptions indicate restrictions to the default | ||||||
|  | 	// permissions, and are typically used in conjunction with | ||||||
|  | 	// user certificates. The standard for SSH certificates | ||||||
|  | 	// defines "force-command" (only allow the given command to | ||||||
|  | 	// execute) and "source-address" (only allow connections from | ||||||
|  | 	// the given address). The SSH package currently only enforces | ||||||
|  | 	// the "source-address" critical option. It is up to server | ||||||
|  | 	// implementations to enforce other critical options, such as | ||||||
|  | 	// "force-command", by checking them after the SSH handshake | ||||||
|  | 	// is successful. In general, SSH servers should reject | ||||||
|  | 	// connections that specify critical options that are unknown | ||||||
|  | 	// or not supported. | ||||||
|  | 	CriticalOptions map[string]string | ||||||
|  |  | ||||||
|  | 	// Extensions are extra functionality that the server may | ||||||
|  | 	// offer on authenticated connections. Lack of support for an | ||||||
|  | 	// extension does not preclude authenticating a user. Common | ||||||
|  | 	// extensions are "permit-agent-forwarding", | ||||||
|  | 	// "permit-X11-forwarding". The Go SSH library currently does | ||||||
|  | 	// not act on any extension, and it is up to server | ||||||
|  | 	// implementations to honor them. Extensions can be used to | ||||||
|  | 	// pass data from the authentication callbacks to the server | ||||||
|  | 	// application layer. | ||||||
|  | 	Extensions map[string]string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ServerConfig holds server specific configuration data. | ||||||
|  | type ServerConfig struct { | ||||||
|  | 	// Config contains configuration shared between client and server. | ||||||
|  | 	Config | ||||||
|  |  | ||||||
|  | 	hostKeys []Signer | ||||||
|  |  | ||||||
|  | 	// NoClientAuth is true if clients are allowed to connect without | ||||||
|  | 	// authenticating. | ||||||
|  | 	NoClientAuth bool | ||||||
|  |  | ||||||
|  | 	// MaxAuthTries specifies the maximum number of authentication attempts | ||||||
|  | 	// permitted per connection. If set to a negative number, the number of | ||||||
|  | 	// attempts are unlimited. If set to zero, the number of attempts are limited | ||||||
|  | 	// to 6. | ||||||
|  | 	MaxAuthTries int | ||||||
|  |  | ||||||
|  | 	// PasswordCallback, if non-nil, is called when a user | ||||||
|  | 	// attempts to authenticate using a password. | ||||||
|  | 	PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error) | ||||||
|  |  | ||||||
|  | 	// PublicKeyCallback, if non-nil, is called when a client | ||||||
|  | 	// offers a public key for authentication. It must return a nil error | ||||||
|  | 	// if the given public key can be used to authenticate the | ||||||
|  | 	// given user. For example, see CertChecker.Authenticate. A | ||||||
|  | 	// call to this function does not guarantee that the key | ||||||
|  | 	// offered is in fact used to authenticate. To record any data | ||||||
|  | 	// depending on the public key, store it inside a | ||||||
|  | 	// Permissions.Extensions entry. | ||||||
|  | 	PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) | ||||||
|  |  | ||||||
|  | 	// KeyboardInteractiveCallback, if non-nil, is called when | ||||||
|  | 	// keyboard-interactive authentication is selected (RFC | ||||||
|  | 	// 4256). The client object's Challenge function should be | ||||||
|  | 	// used to query the user. The callback may offer multiple | ||||||
|  | 	// Challenge rounds. To avoid information leaks, the client | ||||||
|  | 	// should be presented a challenge even if the user is | ||||||
|  | 	// unknown. | ||||||
|  | 	KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error) | ||||||
|  |  | ||||||
|  | 	// AuthLogCallback, if non-nil, is called to log all authentication | ||||||
|  | 	// attempts. | ||||||
|  | 	AuthLogCallback func(conn ConnMetadata, method string, err error) | ||||||
|  |  | ||||||
|  | 	// ServerVersion is the version identification string to announce in | ||||||
|  | 	// the public handshake. | ||||||
|  | 	// If empty, a reasonable default is used. | ||||||
|  | 	// Note that RFC 4253 section 4.2 requires that this string start with | ||||||
|  | 	// "SSH-2.0-". | ||||||
|  | 	ServerVersion string | ||||||
|  |  | ||||||
|  | 	// BannerCallback, if present, is called and the return string is sent to | ||||||
|  | 	// the client after key exchange completed but before authentication. | ||||||
|  | 	BannerCallback func(conn ConnMetadata) string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // AddHostKey adds a private key as a host key. If an existing host | ||||||
|  | // key exists with the same algorithm, it is overwritten. Each server | ||||||
|  | // config must have at least one host key. | ||||||
|  | func (s *ServerConfig) AddHostKey(key Signer) { | ||||||
|  | 	for i, k := range s.hostKeys { | ||||||
|  | 		if k.PublicKey().Type() == key.PublicKey().Type() { | ||||||
|  | 			s.hostKeys[i] = key | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	s.hostKeys = append(s.hostKeys, key) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // cachedPubKey contains the results of querying whether a public key is | ||||||
|  | // acceptable for a user. | ||||||
|  | type cachedPubKey struct { | ||||||
|  | 	user       string | ||||||
|  | 	pubKeyData []byte | ||||||
|  | 	result     error | ||||||
|  | 	perms      *Permissions | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const maxCachedPubKeys = 16 | ||||||
|  |  | ||||||
|  | // pubKeyCache caches tests for public keys.  Since SSH clients | ||||||
|  | // will query whether a public key is acceptable before attempting to | ||||||
|  | // authenticate with it, we end up with duplicate queries for public | ||||||
|  | // key validity.  The cache only applies to a single ServerConn. | ||||||
|  | type pubKeyCache struct { | ||||||
|  | 	keys []cachedPubKey | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // get returns the result for a given user/algo/key tuple. | ||||||
|  | func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) { | ||||||
|  | 	for _, k := range c.keys { | ||||||
|  | 		if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) { | ||||||
|  | 			return k, true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return cachedPubKey{}, false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // add adds the given tuple to the cache. | ||||||
|  | func (c *pubKeyCache) add(candidate cachedPubKey) { | ||||||
|  | 	if len(c.keys) < maxCachedPubKeys { | ||||||
|  | 		c.keys = append(c.keys, candidate) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ServerConn is an authenticated SSH connection, as seen from the | ||||||
|  | // server | ||||||
|  | type ServerConn struct { | ||||||
|  | 	Conn | ||||||
|  |  | ||||||
|  | 	// If the succeeding authentication callback returned a | ||||||
|  | 	// non-nil Permissions pointer, it is stored here. | ||||||
|  | 	Permissions *Permissions | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewServerConn starts a new SSH server with c as the underlying | ||||||
|  | // transport.  It starts with a handshake and, if the handshake is | ||||||
|  | // unsuccessful, it closes the connection and returns an error.  The | ||||||
|  | // Request and NewChannel channels must be serviced, or the connection | ||||||
|  | // will hang. | ||||||
|  | func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) { | ||||||
|  | 	fullConf := *config | ||||||
|  | 	fullConf.SetDefaults() | ||||||
|  | 	if fullConf.MaxAuthTries == 0 { | ||||||
|  | 		fullConf.MaxAuthTries = 6 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	s := &connection{ | ||||||
|  | 		sshConn: sshConn{conn: c}, | ||||||
|  | 	} | ||||||
|  | 	perms, err := s.serverHandshake(&fullConf) | ||||||
|  | 	if err != nil { | ||||||
|  | 		c.Close() | ||||||
|  | 		return nil, nil, nil, err | ||||||
|  | 	} | ||||||
|  | 	return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // signAndMarshal signs the data with the appropriate algorithm, | ||||||
|  | // and serializes the result in SSH wire format. | ||||||
|  | func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { | ||||||
|  | 	sig, err := k.Sign(rand, data) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return Marshal(sig), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // handshake performs key exchange and user authentication. | ||||||
|  | func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) { | ||||||
|  | 	if len(config.hostKeys) == 0 { | ||||||
|  | 		return nil, errors.New("ssh: server has no host keys") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil { | ||||||
|  | 		return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if config.ServerVersion != "" { | ||||||
|  | 		s.serverVersion = []byte(config.ServerVersion) | ||||||
|  | 	} else { | ||||||
|  | 		s.serverVersion = []byte(packageVersion) | ||||||
|  | 	} | ||||||
|  | 	var err error | ||||||
|  | 	s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */) | ||||||
|  | 	s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config) | ||||||
|  |  | ||||||
|  | 	if err := s.transport.waitSession(); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// We just did the key change, so the session ID is established. | ||||||
|  | 	s.sessionID = s.transport.getSessionID() | ||||||
|  |  | ||||||
|  | 	var packet []byte | ||||||
|  | 	if packet, err = s.transport.readPacket(); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var serviceRequest serviceRequestMsg | ||||||
|  | 	if err = Unmarshal(packet, &serviceRequest); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if serviceRequest.Service != serviceUserAuth { | ||||||
|  | 		return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating") | ||||||
|  | 	} | ||||||
|  | 	serviceAccept := serviceAcceptMsg{ | ||||||
|  | 		Service: serviceUserAuth, | ||||||
|  | 	} | ||||||
|  | 	if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	perms, err := s.serverAuthenticate(config) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	s.mux = newMux(s.transport) | ||||||
|  | 	return perms, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func isAcceptableAlgo(algo string) bool { | ||||||
|  | 	switch algo { | ||||||
|  | 	case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoED25519, | ||||||
|  | 		CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01: | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func checkSourceAddress(addr net.Addr, sourceAddrs string) error { | ||||||
|  | 	if addr == nil { | ||||||
|  | 		return errors.New("ssh: no address known for client, but source-address match required") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	tcpAddr, ok := addr.(*net.TCPAddr) | ||||||
|  | 	if !ok { | ||||||
|  | 		return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, sourceAddr := range strings.Split(sourceAddrs, ",") { | ||||||
|  | 		if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { | ||||||
|  | 			if allowedIP.Equal(tcpAddr.IP) { | ||||||
|  | 				return nil | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			_, ipNet, err := net.ParseCIDR(sourceAddr) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if ipNet.Contains(tcpAddr.IP) { | ||||||
|  | 				return nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ServerAuthError implements the error interface. It appends any authentication | ||||||
|  | // errors that may occur, and is returned if all of the authentication methods | ||||||
|  | // provided by the user failed to authenticate. | ||||||
|  | type ServerAuthError struct { | ||||||
|  | 	// Errors contains authentication errors returned by the authentication | ||||||
|  | 	// callback methods. | ||||||
|  | 	Errors []error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l ServerAuthError) Error() string { | ||||||
|  | 	var errs []string | ||||||
|  | 	for _, err := range l.Errors { | ||||||
|  | 		errs = append(errs, err.Error()) | ||||||
|  | 	} | ||||||
|  | 	return "[" + strings.Join(errs, ", ") + "]" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { | ||||||
|  | 	sessionID := s.transport.getSessionID() | ||||||
|  | 	var cache pubKeyCache | ||||||
|  | 	var perms *Permissions | ||||||
|  |  | ||||||
|  | 	authFailures := 0 | ||||||
|  | 	var authErrs []error | ||||||
|  | 	var displayedBanner bool | ||||||
|  |  | ||||||
|  | userAuthLoop: | ||||||
|  | 	for { | ||||||
|  | 		if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 { | ||||||
|  | 			discMsg := &disconnectMsg{ | ||||||
|  | 				Reason:  2, | ||||||
|  | 				Message: "too many authentication failures", | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if err := s.transport.writePacket(Marshal(discMsg)); err != nil { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return nil, discMsg | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var userAuthReq userAuthRequestMsg | ||||||
|  | 		if packet, err := s.transport.readPacket(); err != nil { | ||||||
|  | 			if err == io.EOF { | ||||||
|  | 				return nil, &ServerAuthError{Errors: authErrs} | ||||||
|  | 			} | ||||||
|  | 			return nil, err | ||||||
|  | 		} else if err = Unmarshal(packet, &userAuthReq); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if userAuthReq.Service != serviceSSH { | ||||||
|  | 			return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		s.user = userAuthReq.User | ||||||
|  |  | ||||||
|  | 		if !displayedBanner && config.BannerCallback != nil { | ||||||
|  | 			displayedBanner = true | ||||||
|  | 			msg := config.BannerCallback(s) | ||||||
|  | 			if msg != "" { | ||||||
|  | 				bannerMsg := &userAuthBannerMsg{ | ||||||
|  | 					Message: msg, | ||||||
|  | 				} | ||||||
|  | 				if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil { | ||||||
|  | 					return nil, err | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		perms = nil | ||||||
|  | 		authErr := errors.New("no auth passed yet") | ||||||
|  |  | ||||||
|  | 		switch userAuthReq.Method { | ||||||
|  | 		case "none": | ||||||
|  | 			if config.NoClientAuth { | ||||||
|  | 				authErr = nil | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// allow initial attempt of 'none' without penalty | ||||||
|  | 			if authFailures == 0 { | ||||||
|  | 				authFailures-- | ||||||
|  | 			} | ||||||
|  | 		case "password": | ||||||
|  | 			if config.PasswordCallback == nil { | ||||||
|  | 				authErr = errors.New("ssh: password auth not configured") | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 			payload := userAuthReq.Payload | ||||||
|  | 			if len(payload) < 1 || payload[0] != 0 { | ||||||
|  | 				return nil, parseError(msgUserAuthRequest) | ||||||
|  | 			} | ||||||
|  | 			payload = payload[1:] | ||||||
|  | 			password, payload, ok := parseString(payload) | ||||||
|  | 			if !ok || len(payload) > 0 { | ||||||
|  | 				return nil, parseError(msgUserAuthRequest) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			perms, authErr = config.PasswordCallback(s, password) | ||||||
|  | 		case "keyboard-interactive": | ||||||
|  | 			if config.KeyboardInteractiveCallback == nil { | ||||||
|  | 				authErr = errors.New("ssh: keyboard-interactive auth not configubred") | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			prompter := &sshClientKeyboardInteractive{s} | ||||||
|  | 			perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge) | ||||||
|  | 		case "publickey": | ||||||
|  | 			if config.PublicKeyCallback == nil { | ||||||
|  | 				authErr = errors.New("ssh: publickey auth not configured") | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 			payload := userAuthReq.Payload | ||||||
|  | 			if len(payload) < 1 { | ||||||
|  | 				return nil, parseError(msgUserAuthRequest) | ||||||
|  | 			} | ||||||
|  | 			isQuery := payload[0] == 0 | ||||||
|  | 			payload = payload[1:] | ||||||
|  | 			algoBytes, payload, ok := parseString(payload) | ||||||
|  | 			if !ok { | ||||||
|  | 				return nil, parseError(msgUserAuthRequest) | ||||||
|  | 			} | ||||||
|  | 			algo := string(algoBytes) | ||||||
|  | 			if !isAcceptableAlgo(algo) { | ||||||
|  | 				authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo) | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			pubKeyData, payload, ok := parseString(payload) | ||||||
|  | 			if !ok { | ||||||
|  | 				return nil, parseError(msgUserAuthRequest) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			pubKey, err := ParsePublicKey(pubKeyData) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			candidate, ok := cache.get(s.user, pubKeyData) | ||||||
|  | 			if !ok { | ||||||
|  | 				candidate.user = s.user | ||||||
|  | 				candidate.pubKeyData = pubKeyData | ||||||
|  | 				candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey) | ||||||
|  | 				if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" { | ||||||
|  | 					candidate.result = checkSourceAddress( | ||||||
|  | 						s.RemoteAddr(), | ||||||
|  | 						candidate.perms.CriticalOptions[sourceAddressCriticalOption]) | ||||||
|  | 				} | ||||||
|  | 				cache.add(candidate) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if isQuery { | ||||||
|  | 				// The client can query if the given public key | ||||||
|  | 				// would be okay. | ||||||
|  |  | ||||||
|  | 				if len(payload) > 0 { | ||||||
|  | 					return nil, parseError(msgUserAuthRequest) | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if candidate.result == nil { | ||||||
|  | 					okMsg := userAuthPubKeyOkMsg{ | ||||||
|  | 						Algo:   algo, | ||||||
|  | 						PubKey: pubKeyData, | ||||||
|  | 					} | ||||||
|  | 					if err = s.transport.writePacket(Marshal(&okMsg)); err != nil { | ||||||
|  | 						return nil, err | ||||||
|  | 					} | ||||||
|  | 					continue userAuthLoop | ||||||
|  | 				} | ||||||
|  | 				authErr = candidate.result | ||||||
|  | 			} else { | ||||||
|  | 				sig, payload, ok := parseSignature(payload) | ||||||
|  | 				if !ok || len(payload) > 0 { | ||||||
|  | 					return nil, parseError(msgUserAuthRequest) | ||||||
|  | 				} | ||||||
|  | 				// Ensure the public key algo and signature algo | ||||||
|  | 				// are supported.  Compare the private key | ||||||
|  | 				// algorithm name that corresponds to algo with | ||||||
|  | 				// sig.Format.  This is usually the same, but | ||||||
|  | 				// for certs, the names differ. | ||||||
|  | 				if !isAcceptableAlgo(sig.Format) { | ||||||
|  | 					break | ||||||
|  | 				} | ||||||
|  | 				signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) | ||||||
|  |  | ||||||
|  | 				if err := pubKey.Verify(signedData, sig); err != nil { | ||||||
|  | 					return nil, err | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				authErr = candidate.result | ||||||
|  | 				perms = candidate.perms | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		authErrs = append(authErrs, authErr) | ||||||
|  |  | ||||||
|  | 		if config.AuthLogCallback != nil { | ||||||
|  | 			config.AuthLogCallback(s, userAuthReq.Method, authErr) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if authErr == nil { | ||||||
|  | 			break userAuthLoop | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		authFailures++ | ||||||
|  |  | ||||||
|  | 		var failureMsg userAuthFailureMsg | ||||||
|  | 		if config.PasswordCallback != nil { | ||||||
|  | 			failureMsg.Methods = append(failureMsg.Methods, "password") | ||||||
|  | 		} | ||||||
|  | 		if config.PublicKeyCallback != nil { | ||||||
|  | 			failureMsg.Methods = append(failureMsg.Methods, "publickey") | ||||||
|  | 		} | ||||||
|  | 		if config.KeyboardInteractiveCallback != nil { | ||||||
|  | 			failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if len(failureMsg.Methods) == 0 { | ||||||
|  | 			return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return perms, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by | ||||||
|  | // asking the client on the other side of a ServerConn. | ||||||
|  | type sshClientKeyboardInteractive struct { | ||||||
|  | 	*connection | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) { | ||||||
|  | 	if len(questions) != len(echos) { | ||||||
|  | 		return nil, errors.New("ssh: echos and questions must have equal length") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var prompts []byte | ||||||
|  | 	for i := range questions { | ||||||
|  | 		prompts = appendString(prompts, questions[i]) | ||||||
|  | 		prompts = appendBool(prompts, echos[i]) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{ | ||||||
|  | 		Instruction: instruction, | ||||||
|  | 		NumPrompts:  uint32(len(questions)), | ||||||
|  | 		Prompts:     prompts, | ||||||
|  | 	})); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	packet, err := c.transport.readPacket() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if packet[0] != msgUserAuthInfoResponse { | ||||||
|  | 		return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0]) | ||||||
|  | 	} | ||||||
|  | 	packet = packet[1:] | ||||||
|  |  | ||||||
|  | 	n, packet, ok := parseUint32(packet) | ||||||
|  | 	if !ok || int(n) != len(questions) { | ||||||
|  | 		return nil, parseError(msgUserAuthInfoResponse) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for i := uint32(0); i < n; i++ { | ||||||
|  | 		ans, rest, ok := parseString(packet) | ||||||
|  | 		if !ok { | ||||||
|  | 			return nil, parseError(msgUserAuthInfoResponse) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		answers = append(answers, string(ans)) | ||||||
|  | 		packet = rest | ||||||
|  | 	} | ||||||
|  | 	if len(packet) != 0 { | ||||||
|  | 		return nil, errors.New("ssh: junk at end of message") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return answers, nil | ||||||
|  | } | ||||||
							
								
								
									
										647
									
								
								vendor/golang.org/x/crypto/ssh/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										647
									
								
								vendor/golang.org/x/crypto/ssh/session.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,647 @@ | |||||||
|  | // 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 | ||||||
|  |  | ||||||
|  | // Session implements an interactive session described in | ||||||
|  | // "RFC 4254, section 6". | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"sync" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Signal string | ||||||
|  |  | ||||||
|  | // POSIX signals as listed in RFC 4254 Section 6.10. | ||||||
|  | const ( | ||||||
|  | 	SIGABRT Signal = "ABRT" | ||||||
|  | 	SIGALRM Signal = "ALRM" | ||||||
|  | 	SIGFPE  Signal = "FPE" | ||||||
|  | 	SIGHUP  Signal = "HUP" | ||||||
|  | 	SIGILL  Signal = "ILL" | ||||||
|  | 	SIGINT  Signal = "INT" | ||||||
|  | 	SIGKILL Signal = "KILL" | ||||||
|  | 	SIGPIPE Signal = "PIPE" | ||||||
|  | 	SIGQUIT Signal = "QUIT" | ||||||
|  | 	SIGSEGV Signal = "SEGV" | ||||||
|  | 	SIGTERM Signal = "TERM" | ||||||
|  | 	SIGUSR1 Signal = "USR1" | ||||||
|  | 	SIGUSR2 Signal = "USR2" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var signals = map[Signal]int{ | ||||||
|  | 	SIGABRT: 6, | ||||||
|  | 	SIGALRM: 14, | ||||||
|  | 	SIGFPE:  8, | ||||||
|  | 	SIGHUP:  1, | ||||||
|  | 	SIGILL:  4, | ||||||
|  | 	SIGINT:  2, | ||||||
|  | 	SIGKILL: 9, | ||||||
|  | 	SIGPIPE: 13, | ||||||
|  | 	SIGQUIT: 3, | ||||||
|  | 	SIGSEGV: 11, | ||||||
|  | 	SIGTERM: 15, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type TerminalModes map[uint8]uint32 | ||||||
|  |  | ||||||
|  | // POSIX terminal mode flags as listed in RFC 4254 Section 8. | ||||||
|  | const ( | ||||||
|  | 	tty_OP_END    = 0 | ||||||
|  | 	VINTR         = 1 | ||||||
|  | 	VQUIT         = 2 | ||||||
|  | 	VERASE        = 3 | ||||||
|  | 	VKILL         = 4 | ||||||
|  | 	VEOF          = 5 | ||||||
|  | 	VEOL          = 6 | ||||||
|  | 	VEOL2         = 7 | ||||||
|  | 	VSTART        = 8 | ||||||
|  | 	VSTOP         = 9 | ||||||
|  | 	VSUSP         = 10 | ||||||
|  | 	VDSUSP        = 11 | ||||||
|  | 	VREPRINT      = 12 | ||||||
|  | 	VWERASE       = 13 | ||||||
|  | 	VLNEXT        = 14 | ||||||
|  | 	VFLUSH        = 15 | ||||||
|  | 	VSWTCH        = 16 | ||||||
|  | 	VSTATUS       = 17 | ||||||
|  | 	VDISCARD      = 18 | ||||||
|  | 	IGNPAR        = 30 | ||||||
|  | 	PARMRK        = 31 | ||||||
|  | 	INPCK         = 32 | ||||||
|  | 	ISTRIP        = 33 | ||||||
|  | 	INLCR         = 34 | ||||||
|  | 	IGNCR         = 35 | ||||||
|  | 	ICRNL         = 36 | ||||||
|  | 	IUCLC         = 37 | ||||||
|  | 	IXON          = 38 | ||||||
|  | 	IXANY         = 39 | ||||||
|  | 	IXOFF         = 40 | ||||||
|  | 	IMAXBEL       = 41 | ||||||
|  | 	ISIG          = 50 | ||||||
|  | 	ICANON        = 51 | ||||||
|  | 	XCASE         = 52 | ||||||
|  | 	ECHO          = 53 | ||||||
|  | 	ECHOE         = 54 | ||||||
|  | 	ECHOK         = 55 | ||||||
|  | 	ECHONL        = 56 | ||||||
|  | 	NOFLSH        = 57 | ||||||
|  | 	TOSTOP        = 58 | ||||||
|  | 	IEXTEN        = 59 | ||||||
|  | 	ECHOCTL       = 60 | ||||||
|  | 	ECHOKE        = 61 | ||||||
|  | 	PENDIN        = 62 | ||||||
|  | 	OPOST         = 70 | ||||||
|  | 	OLCUC         = 71 | ||||||
|  | 	ONLCR         = 72 | ||||||
|  | 	OCRNL         = 73 | ||||||
|  | 	ONOCR         = 74 | ||||||
|  | 	ONLRET        = 75 | ||||||
|  | 	CS7           = 90 | ||||||
|  | 	CS8           = 91 | ||||||
|  | 	PARENB        = 92 | ||||||
|  | 	PARODD        = 93 | ||||||
|  | 	TTY_OP_ISPEED = 128 | ||||||
|  | 	TTY_OP_OSPEED = 129 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // A Session represents a connection to a remote command or shell. | ||||||
|  | type Session struct { | ||||||
|  | 	// Stdin specifies the remote process's standard input. | ||||||
|  | 	// If Stdin is nil, the remote process reads from an empty | ||||||
|  | 	// bytes.Buffer. | ||||||
|  | 	Stdin io.Reader | ||||||
|  |  | ||||||
|  | 	// Stdout and Stderr specify the remote process's standard | ||||||
|  | 	// output and error. | ||||||
|  | 	// | ||||||
|  | 	// If either is nil, Run connects the corresponding file | ||||||
|  | 	// descriptor to an instance of ioutil.Discard. There is a | ||||||
|  | 	// fixed amount of buffering that is shared for the two streams. | ||||||
|  | 	// If either blocks it may eventually cause the remote | ||||||
|  | 	// command to block. | ||||||
|  | 	Stdout io.Writer | ||||||
|  | 	Stderr io.Writer | ||||||
|  |  | ||||||
|  | 	ch        Channel // the channel backing this session | ||||||
|  | 	started   bool    // true once Start, Run or Shell is invoked. | ||||||
|  | 	copyFuncs []func() error | ||||||
|  | 	errors    chan error // one send per copyFunc | ||||||
|  |  | ||||||
|  | 	// true if pipe method is active | ||||||
|  | 	stdinpipe, stdoutpipe, stderrpipe bool | ||||||
|  |  | ||||||
|  | 	// stdinPipeWriter is non-nil if StdinPipe has not been called | ||||||
|  | 	// and Stdin was specified by the user; it is the write end of | ||||||
|  | 	// a pipe connecting Session.Stdin to the stdin channel. | ||||||
|  | 	stdinPipeWriter io.WriteCloser | ||||||
|  |  | ||||||
|  | 	exitStatus chan error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SendRequest sends an out-of-band channel request on the SSH channel | ||||||
|  | // underlying the session. | ||||||
|  | func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { | ||||||
|  | 	return s.ch.SendRequest(name, wantReply, payload) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *Session) Close() error { | ||||||
|  | 	return s.ch.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RFC 4254 Section 6.4. | ||||||
|  | type setenvRequest struct { | ||||||
|  | 	Name  string | ||||||
|  | 	Value string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Setenv sets an environment variable that will be applied to any | ||||||
|  | // command executed by Shell or Run. | ||||||
|  | func (s *Session) Setenv(name, value string) error { | ||||||
|  | 	msg := setenvRequest{ | ||||||
|  | 		Name:  name, | ||||||
|  | 		Value: value, | ||||||
|  | 	} | ||||||
|  | 	ok, err := s.ch.SendRequest("env", true, Marshal(&msg)) | ||||||
|  | 	if err == nil && !ok { | ||||||
|  | 		err = errors.New("ssh: setenv failed") | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RFC 4254 Section 6.2. | ||||||
|  | type ptyRequestMsg struct { | ||||||
|  | 	Term     string | ||||||
|  | 	Columns  uint32 | ||||||
|  | 	Rows     uint32 | ||||||
|  | 	Width    uint32 | ||||||
|  | 	Height   uint32 | ||||||
|  | 	Modelist string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RequestPty requests the association of a pty with the session on the remote host. | ||||||
|  | func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error { | ||||||
|  | 	var tm []byte | ||||||
|  | 	for k, v := range termmodes { | ||||||
|  | 		kv := struct { | ||||||
|  | 			Key byte | ||||||
|  | 			Val uint32 | ||||||
|  | 		}{k, v} | ||||||
|  |  | ||||||
|  | 		tm = append(tm, Marshal(&kv)...) | ||||||
|  | 	} | ||||||
|  | 	tm = append(tm, tty_OP_END) | ||||||
|  | 	req := ptyRequestMsg{ | ||||||
|  | 		Term:     term, | ||||||
|  | 		Columns:  uint32(w), | ||||||
|  | 		Rows:     uint32(h), | ||||||
|  | 		Width:    uint32(w * 8), | ||||||
|  | 		Height:   uint32(h * 8), | ||||||
|  | 		Modelist: string(tm), | ||||||
|  | 	} | ||||||
|  | 	ok, err := s.ch.SendRequest("pty-req", true, Marshal(&req)) | ||||||
|  | 	if err == nil && !ok { | ||||||
|  | 		err = errors.New("ssh: pty-req failed") | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RFC 4254 Section 6.5. | ||||||
|  | type subsystemRequestMsg struct { | ||||||
|  | 	Subsystem string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RequestSubsystem requests the association of a subsystem with the session on the remote host. | ||||||
|  | // A subsystem is a predefined command that runs in the background when the ssh session is initiated | ||||||
|  | func (s *Session) RequestSubsystem(subsystem string) error { | ||||||
|  | 	msg := subsystemRequestMsg{ | ||||||
|  | 		Subsystem: subsystem, | ||||||
|  | 	} | ||||||
|  | 	ok, err := s.ch.SendRequest("subsystem", true, Marshal(&msg)) | ||||||
|  | 	if err == nil && !ok { | ||||||
|  | 		err = errors.New("ssh: subsystem request failed") | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RFC 4254 Section 6.7. | ||||||
|  | type ptyWindowChangeMsg struct { | ||||||
|  | 	Columns uint32 | ||||||
|  | 	Rows    uint32 | ||||||
|  | 	Width   uint32 | ||||||
|  | 	Height  uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WindowChange informs the remote host about a terminal window dimension change to h rows and w columns. | ||||||
|  | func (s *Session) WindowChange(h, w int) error { | ||||||
|  | 	req := ptyWindowChangeMsg{ | ||||||
|  | 		Columns: uint32(w), | ||||||
|  | 		Rows:    uint32(h), | ||||||
|  | 		Width:   uint32(w * 8), | ||||||
|  | 		Height:  uint32(h * 8), | ||||||
|  | 	} | ||||||
|  | 	_, err := s.ch.SendRequest("window-change", false, Marshal(&req)) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RFC 4254 Section 6.9. | ||||||
|  | type signalMsg struct { | ||||||
|  | 	Signal string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Signal sends the given signal to the remote process. | ||||||
|  | // sig is one of the SIG* constants. | ||||||
|  | func (s *Session) Signal(sig Signal) error { | ||||||
|  | 	msg := signalMsg{ | ||||||
|  | 		Signal: string(sig), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	_, err := s.ch.SendRequest("signal", false, Marshal(&msg)) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RFC 4254 Section 6.5. | ||||||
|  | type execMsg struct { | ||||||
|  | 	Command string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Start runs cmd on the remote host. Typically, the remote | ||||||
|  | // server passes cmd to the shell for interpretation. | ||||||
|  | // A Session only accepts one call to Run, Start or Shell. | ||||||
|  | func (s *Session) Start(cmd string) error { | ||||||
|  | 	if s.started { | ||||||
|  | 		return errors.New("ssh: session already started") | ||||||
|  | 	} | ||||||
|  | 	req := execMsg{ | ||||||
|  | 		Command: cmd, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ok, err := s.ch.SendRequest("exec", true, Marshal(&req)) | ||||||
|  | 	if err == nil && !ok { | ||||||
|  | 		err = fmt.Errorf("ssh: command %v failed", cmd) | ||||||
|  | 	} | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return s.start() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Run runs cmd on the remote host. Typically, the remote | ||||||
|  | // server passes cmd to the shell for interpretation. | ||||||
|  | // A Session only accepts one call to Run, Start, Shell, Output, | ||||||
|  | // or CombinedOutput. | ||||||
|  | // | ||||||
|  | // The returned error is nil if the command runs, has no problems | ||||||
|  | // copying stdin, stdout, and stderr, and exits with a zero exit | ||||||
|  | // status. | ||||||
|  | // | ||||||
|  | // If the remote server does not send an exit status, an error of type | ||||||
|  | // *ExitMissingError is returned. If the command completes | ||||||
|  | // unsuccessfully or is interrupted by a signal, the error is of type | ||||||
|  | // *ExitError. Other error types may be returned for I/O problems. | ||||||
|  | func (s *Session) Run(cmd string) error { | ||||||
|  | 	err := s.Start(cmd) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return s.Wait() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Output runs cmd on the remote host and returns its standard output. | ||||||
|  | func (s *Session) Output(cmd string) ([]byte, error) { | ||||||
|  | 	if s.Stdout != nil { | ||||||
|  | 		return nil, errors.New("ssh: Stdout already set") | ||||||
|  | 	} | ||||||
|  | 	var b bytes.Buffer | ||||||
|  | 	s.Stdout = &b | ||||||
|  | 	err := s.Run(cmd) | ||||||
|  | 	return b.Bytes(), err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type singleWriter struct { | ||||||
|  | 	b  bytes.Buffer | ||||||
|  | 	mu sync.Mutex | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w *singleWriter) Write(p []byte) (int, error) { | ||||||
|  | 	w.mu.Lock() | ||||||
|  | 	defer w.mu.Unlock() | ||||||
|  | 	return w.b.Write(p) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CombinedOutput runs cmd on the remote host and returns its combined | ||||||
|  | // standard output and standard error. | ||||||
|  | func (s *Session) CombinedOutput(cmd string) ([]byte, error) { | ||||||
|  | 	if s.Stdout != nil { | ||||||
|  | 		return nil, errors.New("ssh: Stdout already set") | ||||||
|  | 	} | ||||||
|  | 	if s.Stderr != nil { | ||||||
|  | 		return nil, errors.New("ssh: Stderr already set") | ||||||
|  | 	} | ||||||
|  | 	var b singleWriter | ||||||
|  | 	s.Stdout = &b | ||||||
|  | 	s.Stderr = &b | ||||||
|  | 	err := s.Run(cmd) | ||||||
|  | 	return b.b.Bytes(), err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Shell starts a login shell on the remote host. A Session only | ||||||
|  | // accepts one call to Run, Start, Shell, Output, or CombinedOutput. | ||||||
|  | func (s *Session) Shell() error { | ||||||
|  | 	if s.started { | ||||||
|  | 		return errors.New("ssh: session already started") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ok, err := s.ch.SendRequest("shell", true, nil) | ||||||
|  | 	if err == nil && !ok { | ||||||
|  | 		return errors.New("ssh: could not start shell") | ||||||
|  | 	} | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return s.start() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *Session) start() error { | ||||||
|  | 	s.started = true | ||||||
|  |  | ||||||
|  | 	type F func(*Session) | ||||||
|  | 	for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} { | ||||||
|  | 		setupFd(s) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	s.errors = make(chan error, len(s.copyFuncs)) | ||||||
|  | 	for _, fn := range s.copyFuncs { | ||||||
|  | 		go func(fn func() error) { | ||||||
|  | 			s.errors <- fn() | ||||||
|  | 		}(fn) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Wait waits for the remote command to exit. | ||||||
|  | // | ||||||
|  | // The returned error is nil if the command runs, has no problems | ||||||
|  | // copying stdin, stdout, and stderr, and exits with a zero exit | ||||||
|  | // status. | ||||||
|  | // | ||||||
|  | // If the remote server does not send an exit status, an error of type | ||||||
|  | // *ExitMissingError is returned. If the command completes | ||||||
|  | // unsuccessfully or is interrupted by a signal, the error is of type | ||||||
|  | // *ExitError. Other error types may be returned for I/O problems. | ||||||
|  | func (s *Session) Wait() error { | ||||||
|  | 	if !s.started { | ||||||
|  | 		return errors.New("ssh: session not started") | ||||||
|  | 	} | ||||||
|  | 	waitErr := <-s.exitStatus | ||||||
|  |  | ||||||
|  | 	if s.stdinPipeWriter != nil { | ||||||
|  | 		s.stdinPipeWriter.Close() | ||||||
|  | 	} | ||||||
|  | 	var copyError error | ||||||
|  | 	for range s.copyFuncs { | ||||||
|  | 		if err := <-s.errors; err != nil && copyError == nil { | ||||||
|  | 			copyError = err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if waitErr != nil { | ||||||
|  | 		return waitErr | ||||||
|  | 	} | ||||||
|  | 	return copyError | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *Session) wait(reqs <-chan *Request) error { | ||||||
|  | 	wm := Waitmsg{status: -1} | ||||||
|  | 	// Wait for msg channel to be closed before returning. | ||||||
|  | 	for msg := range reqs { | ||||||
|  | 		switch msg.Type { | ||||||
|  | 		case "exit-status": | ||||||
|  | 			wm.status = int(binary.BigEndian.Uint32(msg.Payload)) | ||||||
|  | 		case "exit-signal": | ||||||
|  | 			var sigval struct { | ||||||
|  | 				Signal     string | ||||||
|  | 				CoreDumped bool | ||||||
|  | 				Error      string | ||||||
|  | 				Lang       string | ||||||
|  | 			} | ||||||
|  | 			if err := Unmarshal(msg.Payload, &sigval); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Must sanitize strings? | ||||||
|  | 			wm.signal = sigval.Signal | ||||||
|  | 			wm.msg = sigval.Error | ||||||
|  | 			wm.lang = sigval.Lang | ||||||
|  | 		default: | ||||||
|  | 			// This handles keepalives and matches | ||||||
|  | 			// OpenSSH's behaviour. | ||||||
|  | 			if msg.WantReply { | ||||||
|  | 				msg.Reply(false, nil) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if wm.status == 0 { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	if wm.status == -1 { | ||||||
|  | 		// exit-status was never sent from server | ||||||
|  | 		if wm.signal == "" { | ||||||
|  | 			// signal was not sent either.  RFC 4254 | ||||||
|  | 			// section 6.10 recommends against this | ||||||
|  | 			// behavior, but it is allowed, so we let | ||||||
|  | 			// clients handle it. | ||||||
|  | 			return &ExitMissingError{} | ||||||
|  | 		} | ||||||
|  | 		wm.status = 128 | ||||||
|  | 		if _, ok := signals[Signal(wm.signal)]; ok { | ||||||
|  | 			wm.status += signals[Signal(wm.signal)] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &ExitError{wm} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ExitMissingError is returned if a session is torn down cleanly, but | ||||||
|  | // the server sends no confirmation of the exit status. | ||||||
|  | type ExitMissingError struct{} | ||||||
|  |  | ||||||
|  | func (e *ExitMissingError) Error() string { | ||||||
|  | 	return "wait: remote command exited without exit status or exit signal" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *Session) stdin() { | ||||||
|  | 	if s.stdinpipe { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	var stdin io.Reader | ||||||
|  | 	if s.Stdin == nil { | ||||||
|  | 		stdin = new(bytes.Buffer) | ||||||
|  | 	} else { | ||||||
|  | 		r, w := io.Pipe() | ||||||
|  | 		go func() { | ||||||
|  | 			_, err := io.Copy(w, s.Stdin) | ||||||
|  | 			w.CloseWithError(err) | ||||||
|  | 		}() | ||||||
|  | 		stdin, s.stdinPipeWriter = r, w | ||||||
|  | 	} | ||||||
|  | 	s.copyFuncs = append(s.copyFuncs, func() error { | ||||||
|  | 		_, err := io.Copy(s.ch, stdin) | ||||||
|  | 		if err1 := s.ch.CloseWrite(); err == nil && err1 != io.EOF { | ||||||
|  | 			err = err1 | ||||||
|  | 		} | ||||||
|  | 		return err | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *Session) stdout() { | ||||||
|  | 	if s.stdoutpipe { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if s.Stdout == nil { | ||||||
|  | 		s.Stdout = ioutil.Discard | ||||||
|  | 	} | ||||||
|  | 	s.copyFuncs = append(s.copyFuncs, func() error { | ||||||
|  | 		_, err := io.Copy(s.Stdout, s.ch) | ||||||
|  | 		return err | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *Session) stderr() { | ||||||
|  | 	if s.stderrpipe { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if s.Stderr == nil { | ||||||
|  | 		s.Stderr = ioutil.Discard | ||||||
|  | 	} | ||||||
|  | 	s.copyFuncs = append(s.copyFuncs, func() error { | ||||||
|  | 		_, err := io.Copy(s.Stderr, s.ch.Stderr()) | ||||||
|  | 		return err | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // sessionStdin reroutes Close to CloseWrite. | ||||||
|  | type sessionStdin struct { | ||||||
|  | 	io.Writer | ||||||
|  | 	ch Channel | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *sessionStdin) Close() error { | ||||||
|  | 	return s.ch.CloseWrite() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // StdinPipe returns a pipe that will be connected to the | ||||||
|  | // remote command's standard input when the command starts. | ||||||
|  | func (s *Session) StdinPipe() (io.WriteCloser, error) { | ||||||
|  | 	if s.Stdin != nil { | ||||||
|  | 		return nil, errors.New("ssh: Stdin already set") | ||||||
|  | 	} | ||||||
|  | 	if s.started { | ||||||
|  | 		return nil, errors.New("ssh: StdinPipe after process started") | ||||||
|  | 	} | ||||||
|  | 	s.stdinpipe = true | ||||||
|  | 	return &sessionStdin{s.ch, s.ch}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // StdoutPipe returns a pipe that will be connected to the | ||||||
|  | // remote command's standard output when the command starts. | ||||||
|  | // There is a fixed amount of buffering that is shared between | ||||||
|  | // stdout and stderr streams. If the StdoutPipe reader is | ||||||
|  | // not serviced fast enough it may eventually cause the | ||||||
|  | // remote command to block. | ||||||
|  | func (s *Session) StdoutPipe() (io.Reader, error) { | ||||||
|  | 	if s.Stdout != nil { | ||||||
|  | 		return nil, errors.New("ssh: Stdout already set") | ||||||
|  | 	} | ||||||
|  | 	if s.started { | ||||||
|  | 		return nil, errors.New("ssh: StdoutPipe after process started") | ||||||
|  | 	} | ||||||
|  | 	s.stdoutpipe = true | ||||||
|  | 	return s.ch, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // StderrPipe returns a pipe that will be connected to the | ||||||
|  | // remote command's standard error when the command starts. | ||||||
|  | // There is a fixed amount of buffering that is shared between | ||||||
|  | // stdout and stderr streams. If the StderrPipe reader is | ||||||
|  | // not serviced fast enough it may eventually cause the | ||||||
|  | // remote command to block. | ||||||
|  | func (s *Session) StderrPipe() (io.Reader, error) { | ||||||
|  | 	if s.Stderr != nil { | ||||||
|  | 		return nil, errors.New("ssh: Stderr already set") | ||||||
|  | 	} | ||||||
|  | 	if s.started { | ||||||
|  | 		return nil, errors.New("ssh: StderrPipe after process started") | ||||||
|  | 	} | ||||||
|  | 	s.stderrpipe = true | ||||||
|  | 	return s.ch.Stderr(), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // newSession returns a new interactive session on the remote host. | ||||||
|  | func newSession(ch Channel, reqs <-chan *Request) (*Session, error) { | ||||||
|  | 	s := &Session{ | ||||||
|  | 		ch: ch, | ||||||
|  | 	} | ||||||
|  | 	s.exitStatus = make(chan error, 1) | ||||||
|  | 	go func() { | ||||||
|  | 		s.exitStatus <- s.wait(reqs) | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	return s, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // An ExitError reports unsuccessful completion of a remote command. | ||||||
|  | type ExitError struct { | ||||||
|  | 	Waitmsg | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *ExitError) Error() string { | ||||||
|  | 	return e.Waitmsg.String() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Waitmsg stores the information about an exited remote command | ||||||
|  | // as reported by Wait. | ||||||
|  | type Waitmsg struct { | ||||||
|  | 	status int | ||||||
|  | 	signal string | ||||||
|  | 	msg    string | ||||||
|  | 	lang   string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ExitStatus returns the exit status of the remote command. | ||||||
|  | func (w Waitmsg) ExitStatus() int { | ||||||
|  | 	return w.status | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Signal returns the exit signal of the remote command if | ||||||
|  | // it was terminated violently. | ||||||
|  | func (w Waitmsg) Signal() string { | ||||||
|  | 	return w.signal | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Msg returns the exit message given by the remote command | ||||||
|  | func (w Waitmsg) Msg() string { | ||||||
|  | 	return w.msg | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Lang returns the language tag. See RFC 3066 | ||||||
|  | func (w Waitmsg) Lang() string { | ||||||
|  | 	return w.lang | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (w Waitmsg) String() string { | ||||||
|  | 	str := fmt.Sprintf("Process exited with status %v", w.status) | ||||||
|  | 	if w.signal != "" { | ||||||
|  | 		str += fmt.Sprintf(" from signal %v", w.signal) | ||||||
|  | 	} | ||||||
|  | 	if w.msg != "" { | ||||||
|  | 		str += fmt.Sprintf(". Reason was: %v", w.msg) | ||||||
|  | 	} | ||||||
|  | 	return str | ||||||
|  | } | ||||||
							
								
								
									
										115
									
								
								vendor/golang.org/x/crypto/ssh/streamlocal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								vendor/golang.org/x/crypto/ssh/streamlocal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | |||||||
|  | package ssh | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | 	"net" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message | ||||||
|  | // with "direct-streamlocal@openssh.com" string. | ||||||
|  | // | ||||||
|  | // See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding | ||||||
|  | // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235 | ||||||
|  | type streamLocalChannelOpenDirectMsg struct { | ||||||
|  | 	socketPath string | ||||||
|  | 	reserved0  string | ||||||
|  | 	reserved1  uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message | ||||||
|  | // with "forwarded-streamlocal@openssh.com" string. | ||||||
|  | type forwardedStreamLocalPayload struct { | ||||||
|  | 	SocketPath string | ||||||
|  | 	Reserved0  string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message | ||||||
|  | // with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string. | ||||||
|  | type streamLocalChannelForwardMsg struct { | ||||||
|  | 	socketPath string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ListenUnix is similar to ListenTCP but uses a Unix domain socket. | ||||||
|  | func (c *Client) ListenUnix(socketPath string) (net.Listener, error) { | ||||||
|  | 	m := streamLocalChannelForwardMsg{ | ||||||
|  | 		socketPath, | ||||||
|  | 	} | ||||||
|  | 	// send message | ||||||
|  | 	ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer") | ||||||
|  | 	} | ||||||
|  | 	ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"}) | ||||||
|  |  | ||||||
|  | 	return &unixListener{socketPath, c, ch}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *Client) dialStreamLocal(socketPath string) (Channel, error) { | ||||||
|  | 	msg := streamLocalChannelOpenDirectMsg{ | ||||||
|  | 		socketPath: socketPath, | ||||||
|  | 	} | ||||||
|  | 	ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	go DiscardRequests(in) | ||||||
|  | 	return ch, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type unixListener struct { | ||||||
|  | 	socketPath string | ||||||
|  |  | ||||||
|  | 	conn *Client | ||||||
|  | 	in   <-chan forward | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Accept waits for and returns the next connection to the listener. | ||||||
|  | func (l *unixListener) Accept() (net.Conn, error) { | ||||||
|  | 	s, ok := <-l.in | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, io.EOF | ||||||
|  | 	} | ||||||
|  | 	ch, incoming, err := s.newCh.Accept() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	go DiscardRequests(incoming) | ||||||
|  |  | ||||||
|  | 	return &chanConn{ | ||||||
|  | 		Channel: ch, | ||||||
|  | 		laddr: &net.UnixAddr{ | ||||||
|  | 			Name: l.socketPath, | ||||||
|  | 			Net:  "unix", | ||||||
|  | 		}, | ||||||
|  | 		raddr: &net.UnixAddr{ | ||||||
|  | 			Name: "@", | ||||||
|  | 			Net:  "unix", | ||||||
|  | 		}, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close closes the listener. | ||||||
|  | func (l *unixListener) Close() error { | ||||||
|  | 	// this also closes the listener. | ||||||
|  | 	l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"}) | ||||||
|  | 	m := streamLocalChannelForwardMsg{ | ||||||
|  | 		l.socketPath, | ||||||
|  | 	} | ||||||
|  | 	ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m)) | ||||||
|  | 	if err == nil && !ok { | ||||||
|  | 		err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed") | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Addr returns the listener's network address. | ||||||
|  | func (l *unixListener) Addr() net.Addr { | ||||||
|  | 	return &net.UnixAddr{ | ||||||
|  | 		Name: l.socketPath, | ||||||
|  | 		Net:  "unix", | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										465
									
								
								vendor/golang.org/x/crypto/ssh/tcpip.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										465
									
								
								vendor/golang.org/x/crypto/ssh/tcpip.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,465 @@ | |||||||
|  | // 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 ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"math/rand" | ||||||
|  | 	"net" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Listen requests the remote peer open a listening socket on | ||||||
|  | // addr. Incoming connections will be available by calling Accept on | ||||||
|  | // the returned net.Listener. The listener must be serviced, or the | ||||||
|  | // SSH connection may hang. | ||||||
|  | // N must be "tcp", "tcp4", "tcp6", or "unix". | ||||||
|  | func (c *Client) Listen(n, addr string) (net.Listener, error) { | ||||||
|  | 	switch n { | ||||||
|  | 	case "tcp", "tcp4", "tcp6": | ||||||
|  | 		laddr, err := net.ResolveTCPAddr(n, addr) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		return c.ListenTCP(laddr) | ||||||
|  | 	case "unix": | ||||||
|  | 		return c.ListenUnix(addr) | ||||||
|  | 	default: | ||||||
|  | 		return nil, fmt.Errorf("ssh: unsupported protocol: %s", n) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Automatic port allocation is broken with OpenSSH before 6.0. See | ||||||
|  | // also https://bugzilla.mindrot.org/show_bug.cgi?id=2017.  In | ||||||
|  | // particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0, | ||||||
|  | // rather than the actual port number. This means you can never open | ||||||
|  | // two different listeners with auto allocated ports. We work around | ||||||
|  | // this by trying explicit ports until we succeed. | ||||||
|  |  | ||||||
|  | const openSSHPrefix = "OpenSSH_" | ||||||
|  |  | ||||||
|  | var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano())) | ||||||
|  |  | ||||||
|  | // isBrokenOpenSSHVersion returns true if the given version string | ||||||
|  | // specifies a version of OpenSSH that is known to have a bug in port | ||||||
|  | // forwarding. | ||||||
|  | func isBrokenOpenSSHVersion(versionStr string) bool { | ||||||
|  | 	i := strings.Index(versionStr, openSSHPrefix) | ||||||
|  | 	if i < 0 { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 	i += len(openSSHPrefix) | ||||||
|  | 	j := i | ||||||
|  | 	for ; j < len(versionStr); j++ { | ||||||
|  | 		if versionStr[j] < '0' || versionStr[j] > '9' { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	version, _ := strconv.Atoi(versionStr[i:j]) | ||||||
|  | 	return version < 6 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // autoPortListenWorkaround simulates automatic port allocation by | ||||||
|  | // trying random ports repeatedly. | ||||||
|  | func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) { | ||||||
|  | 	var sshListener net.Listener | ||||||
|  | 	var err error | ||||||
|  | 	const tries = 10 | ||||||
|  | 	for i := 0; i < tries; i++ { | ||||||
|  | 		addr := *laddr | ||||||
|  | 		addr.Port = 1024 + portRandomizer.Intn(60000) | ||||||
|  | 		sshListener, err = c.ListenTCP(&addr) | ||||||
|  | 		if err == nil { | ||||||
|  | 			laddr.Port = addr.Port | ||||||
|  | 			return sshListener, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RFC 4254 7.1 | ||||||
|  | type channelForwardMsg struct { | ||||||
|  | 	addr  string | ||||||
|  | 	rport uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ListenTCP requests the remote peer open a listening socket | ||||||
|  | // on laddr. Incoming connections will be available by calling | ||||||
|  | // Accept on the returned net.Listener. | ||||||
|  | func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { | ||||||
|  | 	if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) { | ||||||
|  | 		return c.autoPortListenWorkaround(laddr) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	m := channelForwardMsg{ | ||||||
|  | 		laddr.IP.String(), | ||||||
|  | 		uint32(laddr.Port), | ||||||
|  | 	} | ||||||
|  | 	// send message | ||||||
|  | 	ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, errors.New("ssh: tcpip-forward request denied by peer") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// If the original port was 0, then the remote side will | ||||||
|  | 	// supply a real port number in the response. | ||||||
|  | 	if laddr.Port == 0 { | ||||||
|  | 		var p struct { | ||||||
|  | 			Port uint32 | ||||||
|  | 		} | ||||||
|  | 		if err := Unmarshal(resp, &p); err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		laddr.Port = int(p.Port) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Register this forward, using the port number we obtained. | ||||||
|  | 	ch := c.forwards.add(laddr) | ||||||
|  |  | ||||||
|  | 	return &tcpListener{laddr, c, ch}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // forwardList stores a mapping between remote | ||||||
|  | // forward requests and the tcpListeners. | ||||||
|  | type forwardList struct { | ||||||
|  | 	sync.Mutex | ||||||
|  | 	entries []forwardEntry | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // forwardEntry represents an established mapping of a laddr on a | ||||||
|  | // remote ssh server to a channel connected to a tcpListener. | ||||||
|  | type forwardEntry struct { | ||||||
|  | 	laddr net.Addr | ||||||
|  | 	c     chan forward | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // forward represents an incoming forwarded tcpip connection. The | ||||||
|  | // arguments to add/remove/lookup should be address as specified in | ||||||
|  | // the original forward-request. | ||||||
|  | type forward struct { | ||||||
|  | 	newCh NewChannel // the ssh client channel underlying this forward | ||||||
|  | 	raddr net.Addr   // the raddr of the incoming connection | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *forwardList) add(addr net.Addr) chan forward { | ||||||
|  | 	l.Lock() | ||||||
|  | 	defer l.Unlock() | ||||||
|  | 	f := forwardEntry{ | ||||||
|  | 		laddr: addr, | ||||||
|  | 		c:     make(chan forward, 1), | ||||||
|  | 	} | ||||||
|  | 	l.entries = append(l.entries, f) | ||||||
|  | 	return f.c | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // See RFC 4254, section 7.2 | ||||||
|  | type forwardedTCPPayload struct { | ||||||
|  | 	Addr       string | ||||||
|  | 	Port       uint32 | ||||||
|  | 	OriginAddr string | ||||||
|  | 	OriginPort uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // parseTCPAddr parses the originating address from the remote into a *net.TCPAddr. | ||||||
|  | func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) { | ||||||
|  | 	if port == 0 || port > 65535 { | ||||||
|  | 		return nil, fmt.Errorf("ssh: port number out of range: %d", port) | ||||||
|  | 	} | ||||||
|  | 	ip := net.ParseIP(string(addr)) | ||||||
|  | 	if ip == nil { | ||||||
|  | 		return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr) | ||||||
|  | 	} | ||||||
|  | 	return &net.TCPAddr{IP: ip, Port: int(port)}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *forwardList) handleChannels(in <-chan NewChannel) { | ||||||
|  | 	for ch := range in { | ||||||
|  | 		var ( | ||||||
|  | 			laddr net.Addr | ||||||
|  | 			raddr net.Addr | ||||||
|  | 			err   error | ||||||
|  | 		) | ||||||
|  | 		switch channelType := ch.ChannelType(); channelType { | ||||||
|  | 		case "forwarded-tcpip": | ||||||
|  | 			var payload forwardedTCPPayload | ||||||
|  | 			if err = Unmarshal(ch.ExtraData(), &payload); err != nil { | ||||||
|  | 				ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error()) | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// RFC 4254 section 7.2 specifies that incoming | ||||||
|  | 			// addresses should list the address, in string | ||||||
|  | 			// format. It is implied that this should be an IP | ||||||
|  | 			// address, as it would be impossible to connect to it | ||||||
|  | 			// otherwise. | ||||||
|  | 			laddr, err = parseTCPAddr(payload.Addr, payload.Port) | ||||||
|  | 			if err != nil { | ||||||
|  | 				ch.Reject(ConnectionFailed, err.Error()) | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			raddr, err = parseTCPAddr(payload.OriginAddr, payload.OriginPort) | ||||||
|  | 			if err != nil { | ||||||
|  | 				ch.Reject(ConnectionFailed, err.Error()) | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		case "forwarded-streamlocal@openssh.com": | ||||||
|  | 			var payload forwardedStreamLocalPayload | ||||||
|  | 			if err = Unmarshal(ch.ExtraData(), &payload); err != nil { | ||||||
|  | 				ch.Reject(ConnectionFailed, "could not parse forwarded-streamlocal@openssh.com payload: "+err.Error()) | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			laddr = &net.UnixAddr{ | ||||||
|  | 				Name: payload.SocketPath, | ||||||
|  | 				Net:  "unix", | ||||||
|  | 			} | ||||||
|  | 			raddr = &net.UnixAddr{ | ||||||
|  | 				Name: "@", | ||||||
|  | 				Net:  "unix", | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			panic(fmt.Errorf("ssh: unknown channel type %s", channelType)) | ||||||
|  | 		} | ||||||
|  | 		if ok := l.forward(laddr, raddr, ch); !ok { | ||||||
|  | 			// Section 7.2, implementations MUST reject spurious incoming | ||||||
|  | 			// connections. | ||||||
|  | 			ch.Reject(Prohibited, "no forward for address") | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // remove removes the forward entry, and the channel feeding its | ||||||
|  | // listener. | ||||||
|  | func (l *forwardList) remove(addr net.Addr) { | ||||||
|  | 	l.Lock() | ||||||
|  | 	defer l.Unlock() | ||||||
|  | 	for i, f := range l.entries { | ||||||
|  | 		if addr.Network() == f.laddr.Network() && addr.String() == f.laddr.String() { | ||||||
|  | 			l.entries = append(l.entries[:i], l.entries[i+1:]...) | ||||||
|  | 			close(f.c) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // closeAll closes and clears all forwards. | ||||||
|  | func (l *forwardList) closeAll() { | ||||||
|  | 	l.Lock() | ||||||
|  | 	defer l.Unlock() | ||||||
|  | 	for _, f := range l.entries { | ||||||
|  | 		close(f.c) | ||||||
|  | 	} | ||||||
|  | 	l.entries = nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bool { | ||||||
|  | 	l.Lock() | ||||||
|  | 	defer l.Unlock() | ||||||
|  | 	for _, f := range l.entries { | ||||||
|  | 		if laddr.Network() == f.laddr.Network() && laddr.String() == f.laddr.String() { | ||||||
|  | 			f.c <- forward{newCh: ch, raddr: raddr} | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type tcpListener struct { | ||||||
|  | 	laddr *net.TCPAddr | ||||||
|  |  | ||||||
|  | 	conn *Client | ||||||
|  | 	in   <-chan forward | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Accept waits for and returns the next connection to the listener. | ||||||
|  | func (l *tcpListener) Accept() (net.Conn, error) { | ||||||
|  | 	s, ok := <-l.in | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, io.EOF | ||||||
|  | 	} | ||||||
|  | 	ch, incoming, err := s.newCh.Accept() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	go DiscardRequests(incoming) | ||||||
|  |  | ||||||
|  | 	return &chanConn{ | ||||||
|  | 		Channel: ch, | ||||||
|  | 		laddr:   l.laddr, | ||||||
|  | 		raddr:   s.raddr, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close closes the listener. | ||||||
|  | func (l *tcpListener) Close() error { | ||||||
|  | 	m := channelForwardMsg{ | ||||||
|  | 		l.laddr.IP.String(), | ||||||
|  | 		uint32(l.laddr.Port), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// this also closes the listener. | ||||||
|  | 	l.conn.forwards.remove(l.laddr) | ||||||
|  | 	ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m)) | ||||||
|  | 	if err == nil && !ok { | ||||||
|  | 		err = errors.New("ssh: cancel-tcpip-forward failed") | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Addr returns the listener's network address. | ||||||
|  | func (l *tcpListener) Addr() net.Addr { | ||||||
|  | 	return l.laddr | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Dial initiates a connection to the addr from the remote host. | ||||||
|  | // The resulting connection has a zero LocalAddr() and RemoteAddr(). | ||||||
|  | func (c *Client) Dial(n, addr string) (net.Conn, error) { | ||||||
|  | 	var ch Channel | ||||||
|  | 	switch n { | ||||||
|  | 	case "tcp", "tcp4", "tcp6": | ||||||
|  | 		// Parse the address into host and numeric port. | ||||||
|  | 		host, portString, err := net.SplitHostPort(addr) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		port, err := strconv.ParseUint(portString, 10, 16) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		ch, err = c.dial(net.IPv4zero.String(), 0, host, int(port)) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		// Use a zero address for local and remote address. | ||||||
|  | 		zeroAddr := &net.TCPAddr{ | ||||||
|  | 			IP:   net.IPv4zero, | ||||||
|  | 			Port: 0, | ||||||
|  | 		} | ||||||
|  | 		return &chanConn{ | ||||||
|  | 			Channel: ch, | ||||||
|  | 			laddr:   zeroAddr, | ||||||
|  | 			raddr:   zeroAddr, | ||||||
|  | 		}, nil | ||||||
|  | 	case "unix": | ||||||
|  | 		var err error | ||||||
|  | 		ch, err = c.dialStreamLocal(addr) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		return &chanConn{ | ||||||
|  | 			Channel: ch, | ||||||
|  | 			laddr: &net.UnixAddr{ | ||||||
|  | 				Name: "@", | ||||||
|  | 				Net:  "unix", | ||||||
|  | 			}, | ||||||
|  | 			raddr: &net.UnixAddr{ | ||||||
|  | 				Name: addr, | ||||||
|  | 				Net:  "unix", | ||||||
|  | 			}, | ||||||
|  | 		}, nil | ||||||
|  | 	default: | ||||||
|  | 		return nil, fmt.Errorf("ssh: unsupported protocol: %s", n) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DialTCP connects to the remote address raddr on the network net, | ||||||
|  | // which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is used | ||||||
|  | // as the local address for the connection. | ||||||
|  | func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) { | ||||||
|  | 	if laddr == nil { | ||||||
|  | 		laddr = &net.TCPAddr{ | ||||||
|  | 			IP:   net.IPv4zero, | ||||||
|  | 			Port: 0, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &chanConn{ | ||||||
|  | 		Channel: ch, | ||||||
|  | 		laddr:   laddr, | ||||||
|  | 		raddr:   raddr, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RFC 4254 7.2 | ||||||
|  | type channelOpenDirectMsg struct { | ||||||
|  | 	raddr string | ||||||
|  | 	rport uint32 | ||||||
|  | 	laddr string | ||||||
|  | 	lport uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) { | ||||||
|  | 	msg := channelOpenDirectMsg{ | ||||||
|  | 		raddr: raddr, | ||||||
|  | 		rport: uint32(rport), | ||||||
|  | 		laddr: laddr, | ||||||
|  | 		lport: uint32(lport), | ||||||
|  | 	} | ||||||
|  | 	ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	go DiscardRequests(in) | ||||||
|  | 	return ch, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type tcpChan struct { | ||||||
|  | 	Channel // the backing channel | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // chanConn fulfills the net.Conn interface without | ||||||
|  | // the tcpChan having to hold laddr or raddr directly. | ||||||
|  | type chanConn struct { | ||||||
|  | 	Channel | ||||||
|  | 	laddr, raddr net.Addr | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // LocalAddr returns the local network address. | ||||||
|  | func (t *chanConn) LocalAddr() net.Addr { | ||||||
|  | 	return t.laddr | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RemoteAddr returns the remote network address. | ||||||
|  | func (t *chanConn) RemoteAddr() net.Addr { | ||||||
|  | 	return t.raddr | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetDeadline sets the read and write deadlines associated | ||||||
|  | // with the connection. | ||||||
|  | func (t *chanConn) SetDeadline(deadline time.Time) error { | ||||||
|  | 	if err := t.SetReadDeadline(deadline); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return t.SetWriteDeadline(deadline) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetReadDeadline sets the read deadline. | ||||||
|  | // A zero value for t means Read will not time out. | ||||||
|  | // After the deadline, the error from Read will implement net.Error | ||||||
|  | // with Timeout() == true. | ||||||
|  | func (t *chanConn) SetReadDeadline(deadline time.Time) error { | ||||||
|  | 	// for compatibility with previous version, | ||||||
|  | 	// the error message contains "tcpChan" | ||||||
|  | 	return errors.New("ssh: tcpChan: deadline not supported") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetWriteDeadline exists to satisfy the net.Conn interface | ||||||
|  | // but is not implemented by this type.  It always returns an error. | ||||||
|  | func (t *chanConn) SetWriteDeadline(deadline time.Time) error { | ||||||
|  | 	return errors.New("ssh: tcpChan: deadline not supported") | ||||||
|  | } | ||||||
							
								
								
									
										951
									
								
								vendor/golang.org/x/crypto/ssh/terminal/terminal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										951
									
								
								vendor/golang.org/x/crypto/ssh/terminal/terminal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,951 @@ | |||||||
|  | // 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 terminal | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"io" | ||||||
|  | 	"sync" | ||||||
|  | 	"unicode/utf8" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // EscapeCodes contains escape sequences that can be written to the terminal in | ||||||
|  | // order to achieve different styles of text. | ||||||
|  | type EscapeCodes struct { | ||||||
|  | 	// Foreground colors | ||||||
|  | 	Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte | ||||||
|  |  | ||||||
|  | 	// Reset all attributes | ||||||
|  | 	Reset []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var vt100EscapeCodes = EscapeCodes{ | ||||||
|  | 	Black:   []byte{keyEscape, '[', '3', '0', 'm'}, | ||||||
|  | 	Red:     []byte{keyEscape, '[', '3', '1', 'm'}, | ||||||
|  | 	Green:   []byte{keyEscape, '[', '3', '2', 'm'}, | ||||||
|  | 	Yellow:  []byte{keyEscape, '[', '3', '3', 'm'}, | ||||||
|  | 	Blue:    []byte{keyEscape, '[', '3', '4', 'm'}, | ||||||
|  | 	Magenta: []byte{keyEscape, '[', '3', '5', 'm'}, | ||||||
|  | 	Cyan:    []byte{keyEscape, '[', '3', '6', 'm'}, | ||||||
|  | 	White:   []byte{keyEscape, '[', '3', '7', 'm'}, | ||||||
|  |  | ||||||
|  | 	Reset: []byte{keyEscape, '[', '0', 'm'}, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Terminal contains the state for running a VT100 terminal that is capable of | ||||||
|  | // reading lines of input. | ||||||
|  | type Terminal struct { | ||||||
|  | 	// AutoCompleteCallback, if non-null, is called for each keypress with | ||||||
|  | 	// the full input line and the current position of the cursor (in | ||||||
|  | 	// bytes, as an index into |line|). If it returns ok=false, the key | ||||||
|  | 	// press is processed normally. Otherwise it returns a replacement line | ||||||
|  | 	// and the new cursor position. | ||||||
|  | 	AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool) | ||||||
|  |  | ||||||
|  | 	// Escape contains a pointer to the escape codes for this terminal. | ||||||
|  | 	// It's always a valid pointer, although the escape codes themselves | ||||||
|  | 	// may be empty if the terminal doesn't support them. | ||||||
|  | 	Escape *EscapeCodes | ||||||
|  |  | ||||||
|  | 	// lock protects the terminal and the state in this object from | ||||||
|  | 	// concurrent processing of a key press and a Write() call. | ||||||
|  | 	lock sync.Mutex | ||||||
|  |  | ||||||
|  | 	c      io.ReadWriter | ||||||
|  | 	prompt []rune | ||||||
|  |  | ||||||
|  | 	// line is the current line being entered. | ||||||
|  | 	line []rune | ||||||
|  | 	// pos is the logical position of the cursor in line | ||||||
|  | 	pos int | ||||||
|  | 	// echo is true if local echo is enabled | ||||||
|  | 	echo bool | ||||||
|  | 	// pasteActive is true iff there is a bracketed paste operation in | ||||||
|  | 	// progress. | ||||||
|  | 	pasteActive bool | ||||||
|  |  | ||||||
|  | 	// cursorX contains the current X value of the cursor where the left | ||||||
|  | 	// edge is 0. cursorY contains the row number where the first row of | ||||||
|  | 	// the current line is 0. | ||||||
|  | 	cursorX, cursorY int | ||||||
|  | 	// maxLine is the greatest value of cursorY so far. | ||||||
|  | 	maxLine int | ||||||
|  |  | ||||||
|  | 	termWidth, termHeight int | ||||||
|  |  | ||||||
|  | 	// outBuf contains the terminal data to be sent. | ||||||
|  | 	outBuf []byte | ||||||
|  | 	// remainder contains the remainder of any partial key sequences after | ||||||
|  | 	// a read. It aliases into inBuf. | ||||||
|  | 	remainder []byte | ||||||
|  | 	inBuf     [256]byte | ||||||
|  |  | ||||||
|  | 	// history contains previously entered commands so that they can be | ||||||
|  | 	// accessed with the up and down keys. | ||||||
|  | 	history stRingBuffer | ||||||
|  | 	// historyIndex stores the currently accessed history entry, where zero | ||||||
|  | 	// means the immediately previous entry. | ||||||
|  | 	historyIndex int | ||||||
|  | 	// When navigating up and down the history it's possible to return to | ||||||
|  | 	// the incomplete, initial line. That value is stored in | ||||||
|  | 	// historyPending. | ||||||
|  | 	historyPending string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is | ||||||
|  | // a local terminal, that terminal must first have been put into raw mode. | ||||||
|  | // prompt is a string that is written at the start of each input line (i.e. | ||||||
|  | // "> "). | ||||||
|  | func NewTerminal(c io.ReadWriter, prompt string) *Terminal { | ||||||
|  | 	return &Terminal{ | ||||||
|  | 		Escape:       &vt100EscapeCodes, | ||||||
|  | 		c:            c, | ||||||
|  | 		prompt:       []rune(prompt), | ||||||
|  | 		termWidth:    80, | ||||||
|  | 		termHeight:   24, | ||||||
|  | 		echo:         true, | ||||||
|  | 		historyIndex: -1, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	keyCtrlD     = 4 | ||||||
|  | 	keyCtrlU     = 21 | ||||||
|  | 	keyEnter     = '\r' | ||||||
|  | 	keyEscape    = 27 | ||||||
|  | 	keyBackspace = 127 | ||||||
|  | 	keyUnknown   = 0xd800 /* UTF-16 surrogate area */ + iota | ||||||
|  | 	keyUp | ||||||
|  | 	keyDown | ||||||
|  | 	keyLeft | ||||||
|  | 	keyRight | ||||||
|  | 	keyAltLeft | ||||||
|  | 	keyAltRight | ||||||
|  | 	keyHome | ||||||
|  | 	keyEnd | ||||||
|  | 	keyDeleteWord | ||||||
|  | 	keyDeleteLine | ||||||
|  | 	keyClearScreen | ||||||
|  | 	keyPasteStart | ||||||
|  | 	keyPasteEnd | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	crlf       = []byte{'\r', '\n'} | ||||||
|  | 	pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'} | ||||||
|  | 	pasteEnd   = []byte{keyEscape, '[', '2', '0', '1', '~'} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // bytesToKey tries to parse a key sequence from b. If successful, it returns | ||||||
|  | // the key and the remainder of the input. Otherwise it returns utf8.RuneError. | ||||||
|  | func bytesToKey(b []byte, pasteActive bool) (rune, []byte) { | ||||||
|  | 	if len(b) == 0 { | ||||||
|  | 		return utf8.RuneError, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !pasteActive { | ||||||
|  | 		switch b[0] { | ||||||
|  | 		case 1: // ^A | ||||||
|  | 			return keyHome, b[1:] | ||||||
|  | 		case 5: // ^E | ||||||
|  | 			return keyEnd, b[1:] | ||||||
|  | 		case 8: // ^H | ||||||
|  | 			return keyBackspace, b[1:] | ||||||
|  | 		case 11: // ^K | ||||||
|  | 			return keyDeleteLine, b[1:] | ||||||
|  | 		case 12: // ^L | ||||||
|  | 			return keyClearScreen, b[1:] | ||||||
|  | 		case 23: // ^W | ||||||
|  | 			return keyDeleteWord, b[1:] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if b[0] != keyEscape { | ||||||
|  | 		if !utf8.FullRune(b) { | ||||||
|  | 			return utf8.RuneError, b | ||||||
|  | 		} | ||||||
|  | 		r, l := utf8.DecodeRune(b) | ||||||
|  | 		return r, b[l:] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' { | ||||||
|  | 		switch b[2] { | ||||||
|  | 		case 'A': | ||||||
|  | 			return keyUp, b[3:] | ||||||
|  | 		case 'B': | ||||||
|  | 			return keyDown, b[3:] | ||||||
|  | 		case 'C': | ||||||
|  | 			return keyRight, b[3:] | ||||||
|  | 		case 'D': | ||||||
|  | 			return keyLeft, b[3:] | ||||||
|  | 		case 'H': | ||||||
|  | 			return keyHome, b[3:] | ||||||
|  | 		case 'F': | ||||||
|  | 			return keyEnd, b[3:] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' { | ||||||
|  | 		switch b[5] { | ||||||
|  | 		case 'C': | ||||||
|  | 			return keyAltRight, b[6:] | ||||||
|  | 		case 'D': | ||||||
|  | 			return keyAltLeft, b[6:] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) { | ||||||
|  | 		return keyPasteStart, b[6:] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) { | ||||||
|  | 		return keyPasteEnd, b[6:] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// If we get here then we have a key that we don't recognise, or a | ||||||
|  | 	// partial sequence. It's not clear how one should find the end of a | ||||||
|  | 	// sequence without knowing them all, but it seems that [a-zA-Z~] only | ||||||
|  | 	// appears at the end of a sequence. | ||||||
|  | 	for i, c := range b[0:] { | ||||||
|  | 		if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' { | ||||||
|  | 			return keyUnknown, b[i+1:] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return utf8.RuneError, b | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // queue appends data to the end of t.outBuf | ||||||
|  | func (t *Terminal) queue(data []rune) { | ||||||
|  | 	t.outBuf = append(t.outBuf, []byte(string(data))...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'} | ||||||
|  | var space = []rune{' '} | ||||||
|  |  | ||||||
|  | func isPrintable(key rune) bool { | ||||||
|  | 	isInSurrogateArea := key >= 0xd800 && key <= 0xdbff | ||||||
|  | 	return key >= 32 && !isInSurrogateArea | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // moveCursorToPos appends data to t.outBuf which will move the cursor to the | ||||||
|  | // given, logical position in the text. | ||||||
|  | func (t *Terminal) moveCursorToPos(pos int) { | ||||||
|  | 	if !t.echo { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	x := visualLength(t.prompt) + pos | ||||||
|  | 	y := x / t.termWidth | ||||||
|  | 	x = x % t.termWidth | ||||||
|  |  | ||||||
|  | 	up := 0 | ||||||
|  | 	if y < t.cursorY { | ||||||
|  | 		up = t.cursorY - y | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	down := 0 | ||||||
|  | 	if y > t.cursorY { | ||||||
|  | 		down = y - t.cursorY | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	left := 0 | ||||||
|  | 	if x < t.cursorX { | ||||||
|  | 		left = t.cursorX - x | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	right := 0 | ||||||
|  | 	if x > t.cursorX { | ||||||
|  | 		right = x - t.cursorX | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	t.cursorX = x | ||||||
|  | 	t.cursorY = y | ||||||
|  | 	t.move(up, down, left, right) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *Terminal) move(up, down, left, right int) { | ||||||
|  | 	movement := make([]rune, 3*(up+down+left+right)) | ||||||
|  | 	m := movement | ||||||
|  | 	for i := 0; i < up; i++ { | ||||||
|  | 		m[0] = keyEscape | ||||||
|  | 		m[1] = '[' | ||||||
|  | 		m[2] = 'A' | ||||||
|  | 		m = m[3:] | ||||||
|  | 	} | ||||||
|  | 	for i := 0; i < down; i++ { | ||||||
|  | 		m[0] = keyEscape | ||||||
|  | 		m[1] = '[' | ||||||
|  | 		m[2] = 'B' | ||||||
|  | 		m = m[3:] | ||||||
|  | 	} | ||||||
|  | 	for i := 0; i < left; i++ { | ||||||
|  | 		m[0] = keyEscape | ||||||
|  | 		m[1] = '[' | ||||||
|  | 		m[2] = 'D' | ||||||
|  | 		m = m[3:] | ||||||
|  | 	} | ||||||
|  | 	for i := 0; i < right; i++ { | ||||||
|  | 		m[0] = keyEscape | ||||||
|  | 		m[1] = '[' | ||||||
|  | 		m[2] = 'C' | ||||||
|  | 		m = m[3:] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	t.queue(movement) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *Terminal) clearLineToRight() { | ||||||
|  | 	op := []rune{keyEscape, '[', 'K'} | ||||||
|  | 	t.queue(op) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const maxLineLength = 4096 | ||||||
|  |  | ||||||
|  | func (t *Terminal) setLine(newLine []rune, newPos int) { | ||||||
|  | 	if t.echo { | ||||||
|  | 		t.moveCursorToPos(0) | ||||||
|  | 		t.writeLine(newLine) | ||||||
|  | 		for i := len(newLine); i < len(t.line); i++ { | ||||||
|  | 			t.writeLine(space) | ||||||
|  | 		} | ||||||
|  | 		t.moveCursorToPos(newPos) | ||||||
|  | 	} | ||||||
|  | 	t.line = newLine | ||||||
|  | 	t.pos = newPos | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *Terminal) advanceCursor(places int) { | ||||||
|  | 	t.cursorX += places | ||||||
|  | 	t.cursorY += t.cursorX / t.termWidth | ||||||
|  | 	if t.cursorY > t.maxLine { | ||||||
|  | 		t.maxLine = t.cursorY | ||||||
|  | 	} | ||||||
|  | 	t.cursorX = t.cursorX % t.termWidth | ||||||
|  |  | ||||||
|  | 	if places > 0 && t.cursorX == 0 { | ||||||
|  | 		// Normally terminals will advance the current position | ||||||
|  | 		// when writing a character. But that doesn't happen | ||||||
|  | 		// for the last character in a line. However, when | ||||||
|  | 		// writing a character (except a new line) that causes | ||||||
|  | 		// a line wrap, the position will be advanced two | ||||||
|  | 		// places. | ||||||
|  | 		// | ||||||
|  | 		// So, if we are stopping at the end of a line, we | ||||||
|  | 		// need to write a newline so that our cursor can be | ||||||
|  | 		// advanced to the next line. | ||||||
|  | 		t.outBuf = append(t.outBuf, '\r', '\n') | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *Terminal) eraseNPreviousChars(n int) { | ||||||
|  | 	if n == 0 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if t.pos < n { | ||||||
|  | 		n = t.pos | ||||||
|  | 	} | ||||||
|  | 	t.pos -= n | ||||||
|  | 	t.moveCursorToPos(t.pos) | ||||||
|  |  | ||||||
|  | 	copy(t.line[t.pos:], t.line[n+t.pos:]) | ||||||
|  | 	t.line = t.line[:len(t.line)-n] | ||||||
|  | 	if t.echo { | ||||||
|  | 		t.writeLine(t.line[t.pos:]) | ||||||
|  | 		for i := 0; i < n; i++ { | ||||||
|  | 			t.queue(space) | ||||||
|  | 		} | ||||||
|  | 		t.advanceCursor(n) | ||||||
|  | 		t.moveCursorToPos(t.pos) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // countToLeftWord returns then number of characters from the cursor to the | ||||||
|  | // start of the previous word. | ||||||
|  | func (t *Terminal) countToLeftWord() int { | ||||||
|  | 	if t.pos == 0 { | ||||||
|  | 		return 0 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	pos := t.pos - 1 | ||||||
|  | 	for pos > 0 { | ||||||
|  | 		if t.line[pos] != ' ' { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		pos-- | ||||||
|  | 	} | ||||||
|  | 	for pos > 0 { | ||||||
|  | 		if t.line[pos] == ' ' { | ||||||
|  | 			pos++ | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		pos-- | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return t.pos - pos | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // countToRightWord returns then number of characters from the cursor to the | ||||||
|  | // start of the next word. | ||||||
|  | func (t *Terminal) countToRightWord() int { | ||||||
|  | 	pos := t.pos | ||||||
|  | 	for pos < len(t.line) { | ||||||
|  | 		if t.line[pos] == ' ' { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		pos++ | ||||||
|  | 	} | ||||||
|  | 	for pos < len(t.line) { | ||||||
|  | 		if t.line[pos] != ' ' { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		pos++ | ||||||
|  | 	} | ||||||
|  | 	return pos - t.pos | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // visualLength returns the number of visible glyphs in s. | ||||||
|  | func visualLength(runes []rune) int { | ||||||
|  | 	inEscapeSeq := false | ||||||
|  | 	length := 0 | ||||||
|  |  | ||||||
|  | 	for _, r := range runes { | ||||||
|  | 		switch { | ||||||
|  | 		case inEscapeSeq: | ||||||
|  | 			if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') { | ||||||
|  | 				inEscapeSeq = false | ||||||
|  | 			} | ||||||
|  | 		case r == '\x1b': | ||||||
|  | 			inEscapeSeq = true | ||||||
|  | 		default: | ||||||
|  | 			length++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return length | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // handleKey processes the given key and, optionally, returns a line of text | ||||||
|  | // that the user has entered. | ||||||
|  | func (t *Terminal) handleKey(key rune) (line string, ok bool) { | ||||||
|  | 	if t.pasteActive && key != keyEnter { | ||||||
|  | 		t.addKeyToLine(key) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch key { | ||||||
|  | 	case keyBackspace: | ||||||
|  | 		if t.pos == 0 { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		t.eraseNPreviousChars(1) | ||||||
|  | 	case keyAltLeft: | ||||||
|  | 		// move left by a word. | ||||||
|  | 		t.pos -= t.countToLeftWord() | ||||||
|  | 		t.moveCursorToPos(t.pos) | ||||||
|  | 	case keyAltRight: | ||||||
|  | 		// move right by a word. | ||||||
|  | 		t.pos += t.countToRightWord() | ||||||
|  | 		t.moveCursorToPos(t.pos) | ||||||
|  | 	case keyLeft: | ||||||
|  | 		if t.pos == 0 { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		t.pos-- | ||||||
|  | 		t.moveCursorToPos(t.pos) | ||||||
|  | 	case keyRight: | ||||||
|  | 		if t.pos == len(t.line) { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		t.pos++ | ||||||
|  | 		t.moveCursorToPos(t.pos) | ||||||
|  | 	case keyHome: | ||||||
|  | 		if t.pos == 0 { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		t.pos = 0 | ||||||
|  | 		t.moveCursorToPos(t.pos) | ||||||
|  | 	case keyEnd: | ||||||
|  | 		if t.pos == len(t.line) { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		t.pos = len(t.line) | ||||||
|  | 		t.moveCursorToPos(t.pos) | ||||||
|  | 	case keyUp: | ||||||
|  | 		entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1) | ||||||
|  | 		if !ok { | ||||||
|  | 			return "", false | ||||||
|  | 		} | ||||||
|  | 		if t.historyIndex == -1 { | ||||||
|  | 			t.historyPending = string(t.line) | ||||||
|  | 		} | ||||||
|  | 		t.historyIndex++ | ||||||
|  | 		runes := []rune(entry) | ||||||
|  | 		t.setLine(runes, len(runes)) | ||||||
|  | 	case keyDown: | ||||||
|  | 		switch t.historyIndex { | ||||||
|  | 		case -1: | ||||||
|  | 			return | ||||||
|  | 		case 0: | ||||||
|  | 			runes := []rune(t.historyPending) | ||||||
|  | 			t.setLine(runes, len(runes)) | ||||||
|  | 			t.historyIndex-- | ||||||
|  | 		default: | ||||||
|  | 			entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1) | ||||||
|  | 			if ok { | ||||||
|  | 				t.historyIndex-- | ||||||
|  | 				runes := []rune(entry) | ||||||
|  | 				t.setLine(runes, len(runes)) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	case keyEnter: | ||||||
|  | 		t.moveCursorToPos(len(t.line)) | ||||||
|  | 		t.queue([]rune("\r\n")) | ||||||
|  | 		line = string(t.line) | ||||||
|  | 		ok = true | ||||||
|  | 		t.line = t.line[:0] | ||||||
|  | 		t.pos = 0 | ||||||
|  | 		t.cursorX = 0 | ||||||
|  | 		t.cursorY = 0 | ||||||
|  | 		t.maxLine = 0 | ||||||
|  | 	case keyDeleteWord: | ||||||
|  | 		// Delete zero or more spaces and then one or more characters. | ||||||
|  | 		t.eraseNPreviousChars(t.countToLeftWord()) | ||||||
|  | 	case keyDeleteLine: | ||||||
|  | 		// Delete everything from the current cursor position to the | ||||||
|  | 		// end of line. | ||||||
|  | 		for i := t.pos; i < len(t.line); i++ { | ||||||
|  | 			t.queue(space) | ||||||
|  | 			t.advanceCursor(1) | ||||||
|  | 		} | ||||||
|  | 		t.line = t.line[:t.pos] | ||||||
|  | 		t.moveCursorToPos(t.pos) | ||||||
|  | 	case keyCtrlD: | ||||||
|  | 		// Erase the character under the current position. | ||||||
|  | 		// The EOF case when the line is empty is handled in | ||||||
|  | 		// readLine(). | ||||||
|  | 		if t.pos < len(t.line) { | ||||||
|  | 			t.pos++ | ||||||
|  | 			t.eraseNPreviousChars(1) | ||||||
|  | 		} | ||||||
|  | 	case keyCtrlU: | ||||||
|  | 		t.eraseNPreviousChars(t.pos) | ||||||
|  | 	case keyClearScreen: | ||||||
|  | 		// Erases the screen and moves the cursor to the home position. | ||||||
|  | 		t.queue([]rune("\x1b[2J\x1b[H")) | ||||||
|  | 		t.queue(t.prompt) | ||||||
|  | 		t.cursorX, t.cursorY = 0, 0 | ||||||
|  | 		t.advanceCursor(visualLength(t.prompt)) | ||||||
|  | 		t.setLine(t.line, t.pos) | ||||||
|  | 	default: | ||||||
|  | 		if t.AutoCompleteCallback != nil { | ||||||
|  | 			prefix := string(t.line[:t.pos]) | ||||||
|  | 			suffix := string(t.line[t.pos:]) | ||||||
|  |  | ||||||
|  | 			t.lock.Unlock() | ||||||
|  | 			newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key) | ||||||
|  | 			t.lock.Lock() | ||||||
|  |  | ||||||
|  | 			if completeOk { | ||||||
|  | 				t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos])) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if !isPrintable(key) { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if len(t.line) == maxLineLength { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		t.addKeyToLine(key) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // addKeyToLine inserts the given key at the current position in the current | ||||||
|  | // line. | ||||||
|  | func (t *Terminal) addKeyToLine(key rune) { | ||||||
|  | 	if len(t.line) == cap(t.line) { | ||||||
|  | 		newLine := make([]rune, len(t.line), 2*(1+len(t.line))) | ||||||
|  | 		copy(newLine, t.line) | ||||||
|  | 		t.line = newLine | ||||||
|  | 	} | ||||||
|  | 	t.line = t.line[:len(t.line)+1] | ||||||
|  | 	copy(t.line[t.pos+1:], t.line[t.pos:]) | ||||||
|  | 	t.line[t.pos] = key | ||||||
|  | 	if t.echo { | ||||||
|  | 		t.writeLine(t.line[t.pos:]) | ||||||
|  | 	} | ||||||
|  | 	t.pos++ | ||||||
|  | 	t.moveCursorToPos(t.pos) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *Terminal) writeLine(line []rune) { | ||||||
|  | 	for len(line) != 0 { | ||||||
|  | 		remainingOnLine := t.termWidth - t.cursorX | ||||||
|  | 		todo := len(line) | ||||||
|  | 		if todo > remainingOnLine { | ||||||
|  | 			todo = remainingOnLine | ||||||
|  | 		} | ||||||
|  | 		t.queue(line[:todo]) | ||||||
|  | 		t.advanceCursor(visualLength(line[:todo])) | ||||||
|  | 		line = line[todo:] | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n. | ||||||
|  | func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) { | ||||||
|  | 	for len(buf) > 0 { | ||||||
|  | 		i := bytes.IndexByte(buf, '\n') | ||||||
|  | 		todo := len(buf) | ||||||
|  | 		if i >= 0 { | ||||||
|  | 			todo = i | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var nn int | ||||||
|  | 		nn, err = w.Write(buf[:todo]) | ||||||
|  | 		n += nn | ||||||
|  | 		if err != nil { | ||||||
|  | 			return n, err | ||||||
|  | 		} | ||||||
|  | 		buf = buf[todo:] | ||||||
|  |  | ||||||
|  | 		if i >= 0 { | ||||||
|  | 			if _, err = w.Write(crlf); err != nil { | ||||||
|  | 				return n, err | ||||||
|  | 			} | ||||||
|  | 			n++ | ||||||
|  | 			buf = buf[1:] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return n, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *Terminal) Write(buf []byte) (n int, err error) { | ||||||
|  | 	t.lock.Lock() | ||||||
|  | 	defer t.lock.Unlock() | ||||||
|  |  | ||||||
|  | 	if t.cursorX == 0 && t.cursorY == 0 { | ||||||
|  | 		// This is the easy case: there's nothing on the screen that we | ||||||
|  | 		// have to move out of the way. | ||||||
|  | 		return writeWithCRLF(t.c, buf) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// We have a prompt and possibly user input on the screen. We | ||||||
|  | 	// have to clear it first. | ||||||
|  | 	t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */) | ||||||
|  | 	t.cursorX = 0 | ||||||
|  | 	t.clearLineToRight() | ||||||
|  |  | ||||||
|  | 	for t.cursorY > 0 { | ||||||
|  | 		t.move(1 /* up */, 0, 0, 0) | ||||||
|  | 		t.cursorY-- | ||||||
|  | 		t.clearLineToRight() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if _, err = t.c.Write(t.outBuf); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	t.outBuf = t.outBuf[:0] | ||||||
|  |  | ||||||
|  | 	if n, err = writeWithCRLF(t.c, buf); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	t.writeLine(t.prompt) | ||||||
|  | 	if t.echo { | ||||||
|  | 		t.writeLine(t.line) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	t.moveCursorToPos(t.pos) | ||||||
|  |  | ||||||
|  | 	if _, err = t.c.Write(t.outBuf); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	t.outBuf = t.outBuf[:0] | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ReadPassword temporarily changes the prompt and reads a password, without | ||||||
|  | // echo, from the terminal. | ||||||
|  | func (t *Terminal) ReadPassword(prompt string) (line string, err error) { | ||||||
|  | 	t.lock.Lock() | ||||||
|  | 	defer t.lock.Unlock() | ||||||
|  |  | ||||||
|  | 	oldPrompt := t.prompt | ||||||
|  | 	t.prompt = []rune(prompt) | ||||||
|  | 	t.echo = false | ||||||
|  |  | ||||||
|  | 	line, err = t.readLine() | ||||||
|  |  | ||||||
|  | 	t.prompt = oldPrompt | ||||||
|  | 	t.echo = true | ||||||
|  |  | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ReadLine returns a line of input from the terminal. | ||||||
|  | func (t *Terminal) ReadLine() (line string, err error) { | ||||||
|  | 	t.lock.Lock() | ||||||
|  | 	defer t.lock.Unlock() | ||||||
|  |  | ||||||
|  | 	return t.readLine() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *Terminal) readLine() (line string, err error) { | ||||||
|  | 	// t.lock must be held at this point | ||||||
|  |  | ||||||
|  | 	if t.cursorX == 0 && t.cursorY == 0 { | ||||||
|  | 		t.writeLine(t.prompt) | ||||||
|  | 		t.c.Write(t.outBuf) | ||||||
|  | 		t.outBuf = t.outBuf[:0] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	lineIsPasted := t.pasteActive | ||||||
|  |  | ||||||
|  | 	for { | ||||||
|  | 		rest := t.remainder | ||||||
|  | 		lineOk := false | ||||||
|  | 		for !lineOk { | ||||||
|  | 			var key rune | ||||||
|  | 			key, rest = bytesToKey(rest, t.pasteActive) | ||||||
|  | 			if key == utf8.RuneError { | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 			if !t.pasteActive { | ||||||
|  | 				if key == keyCtrlD { | ||||||
|  | 					if len(t.line) == 0 { | ||||||
|  | 						return "", io.EOF | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				if key == keyPasteStart { | ||||||
|  | 					t.pasteActive = true | ||||||
|  | 					if len(t.line) == 0 { | ||||||
|  | 						lineIsPasted = true | ||||||
|  | 					} | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 			} else if key == keyPasteEnd { | ||||||
|  | 				t.pasteActive = false | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			if !t.pasteActive { | ||||||
|  | 				lineIsPasted = false | ||||||
|  | 			} | ||||||
|  | 			line, lineOk = t.handleKey(key) | ||||||
|  | 		} | ||||||
|  | 		if len(rest) > 0 { | ||||||
|  | 			n := copy(t.inBuf[:], rest) | ||||||
|  | 			t.remainder = t.inBuf[:n] | ||||||
|  | 		} else { | ||||||
|  | 			t.remainder = nil | ||||||
|  | 		} | ||||||
|  | 		t.c.Write(t.outBuf) | ||||||
|  | 		t.outBuf = t.outBuf[:0] | ||||||
|  | 		if lineOk { | ||||||
|  | 			if t.echo { | ||||||
|  | 				t.historyIndex = -1 | ||||||
|  | 				t.history.Add(line) | ||||||
|  | 			} | ||||||
|  | 			if lineIsPasted { | ||||||
|  | 				err = ErrPasteIndicator | ||||||
|  | 			} | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// t.remainder is a slice at the beginning of t.inBuf | ||||||
|  | 		// containing a partial key sequence | ||||||
|  | 		readBuf := t.inBuf[len(t.remainder):] | ||||||
|  | 		var n int | ||||||
|  |  | ||||||
|  | 		t.lock.Unlock() | ||||||
|  | 		n, err = t.c.Read(readBuf) | ||||||
|  | 		t.lock.Lock() | ||||||
|  |  | ||||||
|  | 		if err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		t.remainder = t.inBuf[:n+len(t.remainder)] | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetPrompt sets the prompt to be used when reading subsequent lines. | ||||||
|  | func (t *Terminal) SetPrompt(prompt string) { | ||||||
|  | 	t.lock.Lock() | ||||||
|  | 	defer t.lock.Unlock() | ||||||
|  |  | ||||||
|  | 	t.prompt = []rune(prompt) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) { | ||||||
|  | 	// Move cursor to column zero at the start of the line. | ||||||
|  | 	t.move(t.cursorY, 0, t.cursorX, 0) | ||||||
|  | 	t.cursorX, t.cursorY = 0, 0 | ||||||
|  | 	t.clearLineToRight() | ||||||
|  | 	for t.cursorY < numPrevLines { | ||||||
|  | 		// Move down a line | ||||||
|  | 		t.move(0, 1, 0, 0) | ||||||
|  | 		t.cursorY++ | ||||||
|  | 		t.clearLineToRight() | ||||||
|  | 	} | ||||||
|  | 	// Move back to beginning. | ||||||
|  | 	t.move(t.cursorY, 0, 0, 0) | ||||||
|  | 	t.cursorX, t.cursorY = 0, 0 | ||||||
|  |  | ||||||
|  | 	t.queue(t.prompt) | ||||||
|  | 	t.advanceCursor(visualLength(t.prompt)) | ||||||
|  | 	t.writeLine(t.line) | ||||||
|  | 	t.moveCursorToPos(t.pos) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *Terminal) SetSize(width, height int) error { | ||||||
|  | 	t.lock.Lock() | ||||||
|  | 	defer t.lock.Unlock() | ||||||
|  |  | ||||||
|  | 	if width == 0 { | ||||||
|  | 		width = 1 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	oldWidth := t.termWidth | ||||||
|  | 	t.termWidth, t.termHeight = width, height | ||||||
|  |  | ||||||
|  | 	switch { | ||||||
|  | 	case width == oldWidth: | ||||||
|  | 		// If the width didn't change then nothing else needs to be | ||||||
|  | 		// done. | ||||||
|  | 		return nil | ||||||
|  | 	case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0: | ||||||
|  | 		// If there is nothing on current line and no prompt printed, | ||||||
|  | 		// just do nothing | ||||||
|  | 		return nil | ||||||
|  | 	case width < oldWidth: | ||||||
|  | 		// Some terminals (e.g. xterm) will truncate lines that were | ||||||
|  | 		// too long when shinking. Others, (e.g. gnome-terminal) will | ||||||
|  | 		// attempt to wrap them. For the former, repainting t.maxLine | ||||||
|  | 		// works great, but that behaviour goes badly wrong in the case | ||||||
|  | 		// of the latter because they have doubled every full line. | ||||||
|  |  | ||||||
|  | 		// We assume that we are working on a terminal that wraps lines | ||||||
|  | 		// and adjust the cursor position based on every previous line | ||||||
|  | 		// wrapping and turning into two. This causes the prompt on | ||||||
|  | 		// xterms to move upwards, which isn't great, but it avoids a | ||||||
|  | 		// huge mess with gnome-terminal. | ||||||
|  | 		if t.cursorX >= t.termWidth { | ||||||
|  | 			t.cursorX = t.termWidth - 1 | ||||||
|  | 		} | ||||||
|  | 		t.cursorY *= 2 | ||||||
|  | 		t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2) | ||||||
|  | 	case width > oldWidth: | ||||||
|  | 		// If the terminal expands then our position calculations will | ||||||
|  | 		// be wrong in the future because we think the cursor is | ||||||
|  | 		// |t.pos| chars into the string, but there will be a gap at | ||||||
|  | 		// the end of any wrapped line. | ||||||
|  | 		// | ||||||
|  | 		// But the position will actually be correct until we move, so | ||||||
|  | 		// we can move back to the beginning and repaint everything. | ||||||
|  | 		t.clearAndRepaintLinePlusNPrevious(t.maxLine) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	_, err := t.c.Write(t.outBuf) | ||||||
|  | 	t.outBuf = t.outBuf[:0] | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type pasteIndicatorError struct{} | ||||||
|  |  | ||||||
|  | func (pasteIndicatorError) Error() string { | ||||||
|  | 	return "terminal: ErrPasteIndicator not correctly handled" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ErrPasteIndicator may be returned from ReadLine as the error, in addition | ||||||
|  | // to valid line data. It indicates that bracketed paste mode is enabled and | ||||||
|  | // that the returned line consists only of pasted data. Programs may wish to | ||||||
|  | // interpret pasted data more literally than typed data. | ||||||
|  | var ErrPasteIndicator = pasteIndicatorError{} | ||||||
|  |  | ||||||
|  | // SetBracketedPasteMode requests that the terminal bracket paste operations | ||||||
|  | // with markers. Not all terminals support this but, if it is supported, then | ||||||
|  | // enabling this mode will stop any autocomplete callback from running due to | ||||||
|  | // pastes. Additionally, any lines that are completely pasted will be returned | ||||||
|  | // from ReadLine with the error set to ErrPasteIndicator. | ||||||
|  | func (t *Terminal) SetBracketedPasteMode(on bool) { | ||||||
|  | 	if on { | ||||||
|  | 		io.WriteString(t.c, "\x1b[?2004h") | ||||||
|  | 	} else { | ||||||
|  | 		io.WriteString(t.c, "\x1b[?2004l") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stRingBuffer is a ring buffer of strings. | ||||||
|  | type stRingBuffer struct { | ||||||
|  | 	// entries contains max elements. | ||||||
|  | 	entries []string | ||||||
|  | 	max     int | ||||||
|  | 	// head contains the index of the element most recently added to the ring. | ||||||
|  | 	head int | ||||||
|  | 	// size contains the number of elements in the ring. | ||||||
|  | 	size int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *stRingBuffer) Add(a string) { | ||||||
|  | 	if s.entries == nil { | ||||||
|  | 		const defaultNumEntries = 100 | ||||||
|  | 		s.entries = make([]string, defaultNumEntries) | ||||||
|  | 		s.max = defaultNumEntries | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	s.head = (s.head + 1) % s.max | ||||||
|  | 	s.entries[s.head] = a | ||||||
|  | 	if s.size < s.max { | ||||||
|  | 		s.size++ | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NthPreviousEntry returns the value passed to the nth previous call to Add. | ||||||
|  | // If n is zero then the immediately prior value is returned, if one, then the | ||||||
|  | // next most recent, and so on. If such an element doesn't exist then ok is | ||||||
|  | // false. | ||||||
|  | func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) { | ||||||
|  | 	if n >= s.size { | ||||||
|  | 		return "", false | ||||||
|  | 	} | ||||||
|  | 	index := s.head - n | ||||||
|  | 	if index < 0 { | ||||||
|  | 		index += s.max | ||||||
|  | 	} | ||||||
|  | 	return s.entries[index], true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // readPasswordLine reads from reader until it finds \n or io.EOF. | ||||||
|  | // The slice returned does not include the \n. | ||||||
|  | // readPasswordLine also ignores any \r it finds. | ||||||
|  | func readPasswordLine(reader io.Reader) ([]byte, error) { | ||||||
|  | 	var buf [1]byte | ||||||
|  | 	var ret []byte | ||||||
|  |  | ||||||
|  | 	for { | ||||||
|  | 		n, err := reader.Read(buf[:]) | ||||||
|  | 		if n > 0 { | ||||||
|  | 			switch buf[0] { | ||||||
|  | 			case '\n': | ||||||
|  | 				return ret, nil | ||||||
|  | 			case '\r': | ||||||
|  | 				// remove \r from passwords on Windows | ||||||
|  | 			default: | ||||||
|  | 				ret = append(ret, buf[0]) | ||||||
|  | 			} | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if err != nil { | ||||||
|  | 			if err == io.EOF && len(ret) > 0 { | ||||||
|  | 				return ret, nil | ||||||
|  | 			} | ||||||
|  | 			return ret, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										116
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | |||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | // +build darwin dragonfly freebsd linux,!appengine netbsd openbsd | ||||||
|  |  | ||||||
|  | // Package terminal provides support functions for dealing with terminals, as | ||||||
|  | // commonly found on UNIX systems. | ||||||
|  | // | ||||||
|  | // Putting a terminal into raw mode is the most common requirement: | ||||||
|  | // | ||||||
|  | // 	oldState, err := terminal.MakeRaw(0) | ||||||
|  | // 	if err != nil { | ||||||
|  | // 	        panic(err) | ||||||
|  | // 	} | ||||||
|  | // 	defer terminal.Restore(0, oldState) | ||||||
|  | package terminal // import "golang.org/x/crypto/ssh/terminal" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"golang.org/x/sys/unix" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // State contains the state of a terminal. | ||||||
|  | type State struct { | ||||||
|  | 	termios unix.Termios | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsTerminal returns true if the given file descriptor is a terminal. | ||||||
|  | func IsTerminal(fd int) bool { | ||||||
|  | 	_, err := unix.IoctlGetTermios(fd, ioctlReadTermios) | ||||||
|  | 	return err == nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MakeRaw put the terminal connected to the given file descriptor into raw | ||||||
|  | // mode and returns the previous state of the terminal so that it can be | ||||||
|  | // restored. | ||||||
|  | func MakeRaw(fd int) (*State, error) { | ||||||
|  | 	termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	oldState := State{termios: *termios} | ||||||
|  |  | ||||||
|  | 	// This attempts to replicate the behaviour documented for cfmakeraw in | ||||||
|  | 	// the termios(3) manpage. | ||||||
|  | 	termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON | ||||||
|  | 	termios.Oflag &^= unix.OPOST | ||||||
|  | 	termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN | ||||||
|  | 	termios.Cflag &^= unix.CSIZE | unix.PARENB | ||||||
|  | 	termios.Cflag |= unix.CS8 | ||||||
|  | 	termios.Cc[unix.VMIN] = 1 | ||||||
|  | 	termios.Cc[unix.VTIME] = 0 | ||||||
|  | 	if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &oldState, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetState returns the current state of a terminal which may be useful to | ||||||
|  | // restore the terminal after a signal. | ||||||
|  | func GetState(fd int) (*State, error) { | ||||||
|  | 	termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &State{termios: *termios}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Restore restores the terminal connected to the given file descriptor to a | ||||||
|  | // previous state. | ||||||
|  | func Restore(fd int, state *State) error { | ||||||
|  | 	return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetSize returns the dimensions of the given terminal. | ||||||
|  | func GetSize(fd int) (width, height int, err error) { | ||||||
|  | 	ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return -1, -1, err | ||||||
|  | 	} | ||||||
|  | 	return int(ws.Col), int(ws.Row), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // passwordReader is an io.Reader that reads from a specific file descriptor. | ||||||
|  | type passwordReader int | ||||||
|  |  | ||||||
|  | func (r passwordReader) Read(buf []byte) (int, error) { | ||||||
|  | 	return unix.Read(int(r), buf) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ReadPassword reads a line of input from a terminal without local echo.  This | ||||||
|  | // is commonly used for inputting passwords and other sensitive data. The slice | ||||||
|  | // returned does not include the \n. | ||||||
|  | func ReadPassword(fd int) ([]byte, error) { | ||||||
|  | 	termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	newState := *termios | ||||||
|  | 	newState.Lflag &^= unix.ECHO | ||||||
|  | 	newState.Lflag |= unix.ICANON | unix.ISIG | ||||||
|  | 	newState.Iflag |= unix.ICRNL | ||||||
|  | 	if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	defer func() { | ||||||
|  | 		unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	return readPasswordLine(passwordReader(fd)) | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | // Copyright 2013 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. | ||||||
|  |  | ||||||
|  | // +build darwin dragonfly freebsd netbsd openbsd | ||||||
|  |  | ||||||
|  | package terminal | ||||||
|  |  | ||||||
|  | import "golang.org/x/sys/unix" | ||||||
|  |  | ||||||
|  | const ioctlReadTermios = unix.TIOCGETA | ||||||
|  | const ioctlWriteTermios = unix.TIOCSETA | ||||||
							
								
								
									
										10
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | // Copyright 2013 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 terminal | ||||||
|  |  | ||||||
|  | import "golang.org/x/sys/unix" | ||||||
|  |  | ||||||
|  | const ioctlReadTermios = unix.TCGETS | ||||||
|  | const ioctlWriteTermios = unix.TCSETS | ||||||
							
								
								
									
										58
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | // Copyright 2016 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 terminal provides support functions for dealing with terminals, as | ||||||
|  | // commonly found on UNIX systems. | ||||||
|  | // | ||||||
|  | // Putting a terminal into raw mode is the most common requirement: | ||||||
|  | // | ||||||
|  | // 	oldState, err := terminal.MakeRaw(0) | ||||||
|  | // 	if err != nil { | ||||||
|  | // 	        panic(err) | ||||||
|  | // 	} | ||||||
|  | // 	defer terminal.Restore(0, oldState) | ||||||
|  | package terminal | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"runtime" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type State struct{} | ||||||
|  |  | ||||||
|  | // IsTerminal returns true if the given file descriptor is a terminal. | ||||||
|  | func IsTerminal(fd int) bool { | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MakeRaw put the terminal connected to the given file descriptor into raw | ||||||
|  | // mode and returns the previous state of the terminal so that it can be | ||||||
|  | // restored. | ||||||
|  | func MakeRaw(fd int) (*State, error) { | ||||||
|  | 	return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetState returns the current state of a terminal which may be useful to | ||||||
|  | // restore the terminal after a signal. | ||||||
|  | func GetState(fd int) (*State, error) { | ||||||
|  | 	return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Restore restores the terminal connected to the given file descriptor to a | ||||||
|  | // previous state. | ||||||
|  | func Restore(fd int, state *State) error { | ||||||
|  | 	return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetSize returns the dimensions of the given terminal. | ||||||
|  | func GetSize(fd int) (width, height int, err error) { | ||||||
|  | 	return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ReadPassword reads a line of input from a terminal without local echo.  This | ||||||
|  | // is commonly used for inputting passwords and other sensitive data. The slice | ||||||
|  | // returned does not include the \n. | ||||||
|  | func ReadPassword(fd int) ([]byte, error) { | ||||||
|  | 	return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) | ||||||
|  | } | ||||||
							
								
								
									
										128
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | |||||||
|  | // Copyright 2015 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. | ||||||
|  |  | ||||||
|  | // +build solaris | ||||||
|  |  | ||||||
|  | package terminal // import "golang.org/x/crypto/ssh/terminal" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"golang.org/x/sys/unix" | ||||||
|  | 	"io" | ||||||
|  | 	"syscall" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // State contains the state of a terminal. | ||||||
|  | type State struct { | ||||||
|  | 	state *unix.Termios | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsTerminal returns true if the given file descriptor is a terminal. | ||||||
|  | func IsTerminal(fd int) bool { | ||||||
|  | 	_, err := unix.IoctlGetTermio(fd, unix.TCGETA) | ||||||
|  | 	return err == nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ReadPassword reads a line of input from a terminal without local echo.  This | ||||||
|  | // is commonly used for inputting passwords and other sensitive data. The slice | ||||||
|  | // returned does not include the \n. | ||||||
|  | func ReadPassword(fd int) ([]byte, error) { | ||||||
|  | 	// see also: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libast/common/uwin/getpass.c | ||||||
|  | 	val, err := unix.IoctlGetTermios(fd, unix.TCGETS) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	oldState := *val | ||||||
|  |  | ||||||
|  | 	newState := oldState | ||||||
|  | 	newState.Lflag &^= syscall.ECHO | ||||||
|  | 	newState.Lflag |= syscall.ICANON | syscall.ISIG | ||||||
|  | 	newState.Iflag |= syscall.ICRNL | ||||||
|  | 	err = unix.IoctlSetTermios(fd, unix.TCSETS, &newState) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	defer unix.IoctlSetTermios(fd, unix.TCSETS, &oldState) | ||||||
|  |  | ||||||
|  | 	var buf [16]byte | ||||||
|  | 	var ret []byte | ||||||
|  | 	for { | ||||||
|  | 		n, err := syscall.Read(fd, buf[:]) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		if n == 0 { | ||||||
|  | 			if len(ret) == 0 { | ||||||
|  | 				return nil, io.EOF | ||||||
|  | 			} | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		if buf[n-1] == '\n' { | ||||||
|  | 			n-- | ||||||
|  | 		} | ||||||
|  | 		ret = append(ret, buf[:n]...) | ||||||
|  | 		if n < len(buf) { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return ret, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MakeRaw puts the terminal connected to the given file descriptor into raw | ||||||
|  | // mode and returns the previous state of the terminal so that it can be | ||||||
|  | // restored. | ||||||
|  | // see http://cr.illumos.org/~webrev/andy_js/1060/ | ||||||
|  | func MakeRaw(fd int) (*State, error) { | ||||||
|  | 	oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	oldTermios := *oldTermiosPtr | ||||||
|  |  | ||||||
|  | 	newTermios := oldTermios | ||||||
|  | 	newTermios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON | ||||||
|  | 	newTermios.Oflag &^= syscall.OPOST | ||||||
|  | 	newTermios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN | ||||||
|  | 	newTermios.Cflag &^= syscall.CSIZE | syscall.PARENB | ||||||
|  | 	newTermios.Cflag |= syscall.CS8 | ||||||
|  | 	newTermios.Cc[unix.VMIN] = 1 | ||||||
|  | 	newTermios.Cc[unix.VTIME] = 0 | ||||||
|  |  | ||||||
|  | 	if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &State{ | ||||||
|  | 		state: oldTermiosPtr, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Restore restores the terminal connected to the given file descriptor to a | ||||||
|  | // previous state. | ||||||
|  | func Restore(fd int, oldState *State) error { | ||||||
|  | 	return unix.IoctlSetTermios(fd, unix.TCSETS, oldState.state) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetState returns the current state of a terminal which may be useful to | ||||||
|  | // restore the terminal after a signal. | ||||||
|  | func GetState(fd int) (*State, error) { | ||||||
|  | 	oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &State{ | ||||||
|  | 		state: oldTermiosPtr, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetSize returns the dimensions of the given terminal. | ||||||
|  | func GetSize(fd int) (width, height int, err error) { | ||||||
|  | 	ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, 0, err | ||||||
|  | 	} | ||||||
|  | 	return int(ws.Col), int(ws.Row), nil | ||||||
|  | } | ||||||
							
								
								
									
										97
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | |||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | // +build windows | ||||||
|  |  | ||||||
|  | // Package terminal provides support functions for dealing with terminals, as | ||||||
|  | // commonly found on UNIX systems. | ||||||
|  | // | ||||||
|  | // Putting a terminal into raw mode is the most common requirement: | ||||||
|  | // | ||||||
|  | // 	oldState, err := terminal.MakeRaw(0) | ||||||
|  | // 	if err != nil { | ||||||
|  | // 	        panic(err) | ||||||
|  | // 	} | ||||||
|  | // 	defer terminal.Restore(0, oldState) | ||||||
|  | package terminal | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"os" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/sys/windows" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type State struct { | ||||||
|  | 	mode uint32 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IsTerminal returns true if the given file descriptor is a terminal. | ||||||
|  | func IsTerminal(fd int) bool { | ||||||
|  | 	var st uint32 | ||||||
|  | 	err := windows.GetConsoleMode(windows.Handle(fd), &st) | ||||||
|  | 	return err == nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MakeRaw put the terminal connected to the given file descriptor into raw | ||||||
|  | // mode and returns the previous state of the terminal so that it can be | ||||||
|  | // restored. | ||||||
|  | func MakeRaw(fd int) (*State, error) { | ||||||
|  | 	var st uint32 | ||||||
|  | 	if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	raw := st &^ (windows.ENABLE_ECHO_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) | ||||||
|  | 	if err := windows.SetConsoleMode(windows.Handle(fd), raw); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &State{st}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetState returns the current state of a terminal which may be useful to | ||||||
|  | // restore the terminal after a signal. | ||||||
|  | func GetState(fd int) (*State, error) { | ||||||
|  | 	var st uint32 | ||||||
|  | 	if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &State{st}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Restore restores the terminal connected to the given file descriptor to a | ||||||
|  | // previous state. | ||||||
|  | func Restore(fd int, state *State) error { | ||||||
|  | 	return windows.SetConsoleMode(windows.Handle(fd), state.mode) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetSize returns the dimensions of the given terminal. | ||||||
|  | func GetSize(fd int) (width, height int, err error) { | ||||||
|  | 	var info windows.ConsoleScreenBufferInfo | ||||||
|  | 	if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { | ||||||
|  | 		return 0, 0, err | ||||||
|  | 	} | ||||||
|  | 	return int(info.Size.X), int(info.Size.Y), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ReadPassword reads a line of input from a terminal without local echo.  This | ||||||
|  | // is commonly used for inputting passwords and other sensitive data. The slice | ||||||
|  | // returned does not include the \n. | ||||||
|  | func ReadPassword(fd int) ([]byte, error) { | ||||||
|  | 	var st uint32 | ||||||
|  | 	if err := windows.GetConsoleMode(windows.Handle(fd), &st); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	old := st | ||||||
|  |  | ||||||
|  | 	st &^= (windows.ENABLE_ECHO_INPUT) | ||||||
|  | 	st |= (windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) | ||||||
|  | 	if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	defer func() { | ||||||
|  | 		windows.SetConsoleMode(windows.Handle(fd), old) | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	return readPasswordLine(os.NewFile(uintptr(fd), "stdin")) | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								vendor/golang.org/x/crypto/ssh/test/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/golang.org/x/crypto/ssh/test/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | // Copyright 2012 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 test contains integration tests for the | ||||||
|  | // golang.org/x/crypto/ssh package. | ||||||
|  | package test // import "golang.org/x/crypto/ssh/test" | ||||||
							
								
								
									
										375
									
								
								vendor/golang.org/x/crypto/ssh/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										375
									
								
								vendor/golang.org/x/crypto/ssh/transport.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,375 @@ | |||||||
|  | // 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 ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | 	"log" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // debugTransport if set, will print packet types as they go over the | ||||||
|  | // wire. No message decoding is done, to minimize the impact on timing. | ||||||
|  | const debugTransport = false | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	gcmCipherID    = "aes128-gcm@openssh.com" | ||||||
|  | 	aes128cbcID    = "aes128-cbc" | ||||||
|  | 	tripledescbcID = "3des-cbc" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // packetConn represents a transport that implements packet based | ||||||
|  | // operations. | ||||||
|  | type packetConn interface { | ||||||
|  | 	// Encrypt and send a packet of data to the remote peer. | ||||||
|  | 	writePacket(packet []byte) error | ||||||
|  |  | ||||||
|  | 	// Read a packet from the connection. The read is blocking, | ||||||
|  | 	// i.e. if error is nil, then the returned byte slice is | ||||||
|  | 	// always non-empty. | ||||||
|  | 	readPacket() ([]byte, error) | ||||||
|  |  | ||||||
|  | 	// Close closes the write-side of the connection. | ||||||
|  | 	Close() error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // transport is the keyingTransport that implements the SSH packet | ||||||
|  | // protocol. | ||||||
|  | type transport struct { | ||||||
|  | 	reader connectionState | ||||||
|  | 	writer connectionState | ||||||
|  |  | ||||||
|  | 	bufReader *bufio.Reader | ||||||
|  | 	bufWriter *bufio.Writer | ||||||
|  | 	rand      io.Reader | ||||||
|  | 	isClient  bool | ||||||
|  | 	io.Closer | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // packetCipher represents a combination of SSH encryption/MAC | ||||||
|  | // protocol.  A single instance should be used for one direction only. | ||||||
|  | type packetCipher interface { | ||||||
|  | 	// writePacket encrypts the packet and writes it to w. The | ||||||
|  | 	// contents of the packet are generally scrambled. | ||||||
|  | 	writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error | ||||||
|  |  | ||||||
|  | 	// readPacket reads and decrypts a packet of data. The | ||||||
|  | 	// returned packet may be overwritten by future calls of | ||||||
|  | 	// readPacket. | ||||||
|  | 	readPacket(seqnum uint32, r io.Reader) ([]byte, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // connectionState represents one side (read or write) of the | ||||||
|  | // connection. This is necessary because each direction has its own | ||||||
|  | // keys, and can even have its own algorithms | ||||||
|  | type connectionState struct { | ||||||
|  | 	packetCipher | ||||||
|  | 	seqNum           uint32 | ||||||
|  | 	dir              direction | ||||||
|  | 	pendingKeyChange chan packetCipher | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // prepareKeyChange sets up key material for a keychange. The key changes in | ||||||
|  | // both directions are triggered by reading and writing a msgNewKey packet | ||||||
|  | // respectively. | ||||||
|  | func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error { | ||||||
|  | 	ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	t.reader.pendingKeyChange <- ciph | ||||||
|  |  | ||||||
|  | 	ciph, err = newPacketCipher(t.writer.dir, algs.w, kexResult) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	t.writer.pendingKeyChange <- ciph | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *transport) printPacket(p []byte, write bool) { | ||||||
|  | 	if len(p) == 0 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	who := "server" | ||||||
|  | 	if t.isClient { | ||||||
|  | 		who = "client" | ||||||
|  | 	} | ||||||
|  | 	what := "read" | ||||||
|  | 	if write { | ||||||
|  | 		what = "write" | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	log.Println(what, who, p[0]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Read and decrypt next packet. | ||||||
|  | func (t *transport) readPacket() (p []byte, err error) { | ||||||
|  | 	for { | ||||||
|  | 		p, err = t.reader.readPacket(t.bufReader) | ||||||
|  | 		if err != nil { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if debugTransport { | ||||||
|  | 		t.printPacket(p, false) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return p, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { | ||||||
|  | 	packet, err := s.packetCipher.readPacket(s.seqNum, r) | ||||||
|  | 	s.seqNum++ | ||||||
|  | 	if err == nil && len(packet) == 0 { | ||||||
|  | 		err = errors.New("ssh: zero length packet") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(packet) > 0 { | ||||||
|  | 		switch packet[0] { | ||||||
|  | 		case msgNewKeys: | ||||||
|  | 			select { | ||||||
|  | 			case cipher := <-s.pendingKeyChange: | ||||||
|  | 				s.packetCipher = cipher | ||||||
|  | 			default: | ||||||
|  | 				return nil, errors.New("ssh: got bogus newkeys message") | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		case msgDisconnect: | ||||||
|  | 			// Transform a disconnect message into an | ||||||
|  | 			// error. Since this is lowest level at which | ||||||
|  | 			// we interpret message types, doing it here | ||||||
|  | 			// ensures that we don't have to handle it | ||||||
|  | 			// elsewhere. | ||||||
|  | 			var msg disconnectMsg | ||||||
|  | 			if err := Unmarshal(packet, &msg); err != nil { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  | 			return nil, &msg | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// The packet may point to an internal buffer, so copy the | ||||||
|  | 	// packet out here. | ||||||
|  | 	fresh := make([]byte, len(packet)) | ||||||
|  | 	copy(fresh, packet) | ||||||
|  |  | ||||||
|  | 	return fresh, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (t *transport) writePacket(packet []byte) error { | ||||||
|  | 	if debugTransport { | ||||||
|  | 		t.printPacket(packet, true) | ||||||
|  | 	} | ||||||
|  | 	return t.writer.writePacket(t.bufWriter, t.rand, packet) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { | ||||||
|  | 	changeKeys := len(packet) > 0 && packet[0] == msgNewKeys | ||||||
|  |  | ||||||
|  | 	err := s.packetCipher.writePacket(s.seqNum, w, rand, packet) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if err = w.Flush(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	s.seqNum++ | ||||||
|  | 	if changeKeys { | ||||||
|  | 		select { | ||||||
|  | 		case cipher := <-s.pendingKeyChange: | ||||||
|  | 			s.packetCipher = cipher | ||||||
|  | 		default: | ||||||
|  | 			panic("ssh: no key material for msgNewKeys") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport { | ||||||
|  | 	t := &transport{ | ||||||
|  | 		bufReader: bufio.NewReader(rwc), | ||||||
|  | 		bufWriter: bufio.NewWriter(rwc), | ||||||
|  | 		rand:      rand, | ||||||
|  | 		reader: connectionState{ | ||||||
|  | 			packetCipher:     &streamPacketCipher{cipher: noneCipher{}}, | ||||||
|  | 			pendingKeyChange: make(chan packetCipher, 1), | ||||||
|  | 		}, | ||||||
|  | 		writer: connectionState{ | ||||||
|  | 			packetCipher:     &streamPacketCipher{cipher: noneCipher{}}, | ||||||
|  | 			pendingKeyChange: make(chan packetCipher, 1), | ||||||
|  | 		}, | ||||||
|  | 		Closer: rwc, | ||||||
|  | 	} | ||||||
|  | 	t.isClient = isClient | ||||||
|  |  | ||||||
|  | 	if isClient { | ||||||
|  | 		t.reader.dir = serverKeys | ||||||
|  | 		t.writer.dir = clientKeys | ||||||
|  | 	} else { | ||||||
|  | 		t.reader.dir = clientKeys | ||||||
|  | 		t.writer.dir = serverKeys | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return t | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type direction struct { | ||||||
|  | 	ivTag     []byte | ||||||
|  | 	keyTag    []byte | ||||||
|  | 	macKeyTag []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}} | ||||||
|  | 	clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // generateKeys generates key material for IV, MAC and encryption. | ||||||
|  | func generateKeys(d direction, algs directionAlgorithms, kex *kexResult) (iv, key, macKey []byte) { | ||||||
|  | 	cipherMode := cipherModes[algs.Cipher] | ||||||
|  | 	macMode := macModes[algs.MAC] | ||||||
|  |  | ||||||
|  | 	iv = make([]byte, cipherMode.ivSize) | ||||||
|  | 	key = make([]byte, cipherMode.keySize) | ||||||
|  | 	macKey = make([]byte, macMode.keySize) | ||||||
|  |  | ||||||
|  | 	generateKeyMaterial(iv, d.ivTag, kex) | ||||||
|  | 	generateKeyMaterial(key, d.keyTag, kex) | ||||||
|  | 	generateKeyMaterial(macKey, d.macKeyTag, kex) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as | ||||||
|  | // described in RFC 4253, section 6.4. direction should either be serverKeys | ||||||
|  | // (to setup server->client keys) or clientKeys (for client->server keys). | ||||||
|  | func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) { | ||||||
|  | 	iv, key, macKey := generateKeys(d, algs, kex) | ||||||
|  |  | ||||||
|  | 	if algs.Cipher == gcmCipherID { | ||||||
|  | 		return newGCMCipher(iv, key) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if algs.Cipher == aes128cbcID { | ||||||
|  | 		return newAESCBCCipher(iv, key, macKey, algs) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if algs.Cipher == tripledescbcID { | ||||||
|  | 		return newTripleDESCBCCipher(iv, key, macKey, algs) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c := &streamPacketCipher{ | ||||||
|  | 		mac: macModes[algs.MAC].new(macKey), | ||||||
|  | 		etm: macModes[algs.MAC].etm, | ||||||
|  | 	} | ||||||
|  | 	c.macResult = make([]byte, c.mac.Size()) | ||||||
|  |  | ||||||
|  | 	var err error | ||||||
|  | 	c.cipher, err = cipherModes[algs.Cipher].createStream(key, iv) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return c, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // generateKeyMaterial fills out with key material generated from tag, K, H | ||||||
|  | // and sessionId, as specified in RFC 4253, section 7.2. | ||||||
|  | func generateKeyMaterial(out, tag []byte, r *kexResult) { | ||||||
|  | 	var digestsSoFar []byte | ||||||
|  |  | ||||||
|  | 	h := r.Hash.New() | ||||||
|  | 	for len(out) > 0 { | ||||||
|  | 		h.Reset() | ||||||
|  | 		h.Write(r.K) | ||||||
|  | 		h.Write(r.H) | ||||||
|  |  | ||||||
|  | 		if len(digestsSoFar) == 0 { | ||||||
|  | 			h.Write(tag) | ||||||
|  | 			h.Write(r.SessionID) | ||||||
|  | 		} else { | ||||||
|  | 			h.Write(digestsSoFar) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		digest := h.Sum(nil) | ||||||
|  | 		n := copy(out, digest) | ||||||
|  | 		out = out[n:] | ||||||
|  | 		if len(out) > 0 { | ||||||
|  | 			digestsSoFar = append(digestsSoFar, digest...) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const packageVersion = "SSH-2.0-Go" | ||||||
|  |  | ||||||
|  | // Sends and receives a version line.  The versionLine string should | ||||||
|  | // be US ASCII, start with "SSH-2.0-", and should not include a | ||||||
|  | // newline. exchangeVersions returns the other side's version line. | ||||||
|  | func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) { | ||||||
|  | 	// Contrary to the RFC, we do not ignore lines that don't | ||||||
|  | 	// start with "SSH-2.0-" to make the library usable with | ||||||
|  | 	// nonconforming servers. | ||||||
|  | 	for _, c := range versionLine { | ||||||
|  | 		// The spec disallows non US-ASCII chars, and | ||||||
|  | 		// specifically forbids null chars. | ||||||
|  | 		if c < 32 { | ||||||
|  | 			return nil, errors.New("ssh: junk character in version line") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	them, err = readVersion(rw) | ||||||
|  | 	return them, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // maxVersionStringBytes is the maximum number of bytes that we'll | ||||||
|  | // accept as a version string. RFC 4253 section 4.2 limits this at 255 | ||||||
|  | // chars | ||||||
|  | const maxVersionStringBytes = 255 | ||||||
|  |  | ||||||
|  | // Read version string as specified by RFC 4253, section 4.2. | ||||||
|  | func readVersion(r io.Reader) ([]byte, error) { | ||||||
|  | 	versionString := make([]byte, 0, 64) | ||||||
|  | 	var ok bool | ||||||
|  | 	var buf [1]byte | ||||||
|  |  | ||||||
|  | 	for len(versionString) < maxVersionStringBytes { | ||||||
|  | 		_, err := io.ReadFull(r, buf[:]) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		// The RFC says that the version should be terminated with \r\n | ||||||
|  | 		// but several SSH servers actually only send a \n. | ||||||
|  | 		if buf[0] == '\n' { | ||||||
|  | 			ok = true | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// non ASCII chars are disallowed, but we are lenient, | ||||||
|  | 		// since Go doesn't use null-terminated strings. | ||||||
|  |  | ||||||
|  | 		// The RFC allows a comment after a space, however, | ||||||
|  | 		// all of it (version and comments) goes into the | ||||||
|  | 		// session hash. | ||||||
|  | 		versionString = append(versionString, buf[0]) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, errors.New("ssh: overflow reading version string") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// There might be a '\r' on the end which we should remove. | ||||||
|  | 	if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { | ||||||
|  | 		versionString = versionString[:len(versionString)-1] | ||||||
|  | 	} | ||||||
|  | 	return versionString, nil | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								vendor/golang.org/x/sys/unix/asm_openbsd_arm.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/golang.org/x/sys/unix/asm_openbsd_arm.s
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // +build !gccgo | ||||||
|  |  | ||||||
|  | #include "textflag.h" | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // System call support for ARM, OpenBSD | ||||||
|  | // | ||||||
|  |  | ||||||
|  | // Just jump to package syscall's implementation for all these functions. | ||||||
|  | // The runtime may know about them. | ||||||
|  |  | ||||||
|  | TEXT	·Syscall(SB),NOSPLIT,$0-28 | ||||||
|  | 	B	syscall·Syscall(SB) | ||||||
|  |  | ||||||
|  | TEXT	·Syscall6(SB),NOSPLIT,$0-40 | ||||||
|  | 	B	syscall·Syscall6(SB) | ||||||
|  |  | ||||||
|  | TEXT	·Syscall9(SB),NOSPLIT,$0-52 | ||||||
|  | 	B	syscall·Syscall9(SB) | ||||||
|  |  | ||||||
|  | TEXT	·RawSyscall(SB),NOSPLIT,$0-28 | ||||||
|  | 	B	syscall·RawSyscall(SB) | ||||||
|  |  | ||||||
|  | TEXT	·RawSyscall6(SB),NOSPLIT,$0-40 | ||||||
|  | 	B	syscall·RawSyscall6(SB) | ||||||
							
								
								
									
										4
									
								
								vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -10,8 +10,8 @@ | |||||||
| // System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go | // System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go | ||||||
| // | // | ||||||
|  |  | ||||||
| TEXT ·sysvicall6(SB),NOSPLIT,$0-64 | TEXT ·sysvicall6(SB),NOSPLIT,$0-88 | ||||||
| 	JMP	syscall·sysvicall6(SB) | 	JMP	syscall·sysvicall6(SB) | ||||||
|  |  | ||||||
| TEXT ·rawSysvicall6(SB),NOSPLIT,$0-64 | TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88 | ||||||
| 	JMP	syscall·rawSysvicall6(SB) | 	JMP	syscall·rawSysvicall6(SB) | ||||||
|   | |||||||
							
								
								
									
										195
									
								
								vendor/golang.org/x/sys/unix/cap_freebsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								vendor/golang.org/x/sys/unix/cap_freebsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,195 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // +build freebsd | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	errorspkg "errors" | ||||||
|  | 	"fmt" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// This is the version of CapRights this package understands. See C implementation for parallels. | ||||||
|  | 	capRightsGoVersion = CAP_RIGHTS_VERSION_00 | ||||||
|  | 	capArSizeMin       = CAP_RIGHTS_VERSION_00 + 2 | ||||||
|  | 	capArSizeMax       = capRightsGoVersion + 2 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	bit2idx = []int{ | ||||||
|  | 		-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, | ||||||
|  | 		4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func capidxbit(right uint64) int { | ||||||
|  | 	return int((right >> 57) & 0x1f) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func rightToIndex(right uint64) (int, error) { | ||||||
|  | 	idx := capidxbit(right) | ||||||
|  | 	if idx < 0 || idx >= len(bit2idx) { | ||||||
|  | 		return -2, fmt.Errorf("index for right 0x%x out of range", right) | ||||||
|  | 	} | ||||||
|  | 	return bit2idx[idx], nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func caprver(right uint64) int { | ||||||
|  | 	return int(right >> 62) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func capver(rights *CapRights) int { | ||||||
|  | 	return caprver(rights.Rights[0]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func caparsize(rights *CapRights) int { | ||||||
|  | 	return capver(rights) + 2 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CapRightsSet sets the permissions in setrights in rights. | ||||||
|  | func CapRightsSet(rights *CapRights, setrights []uint64) error { | ||||||
|  | 	// This is essentially a copy of cap_rights_vset() | ||||||
|  | 	if capver(rights) != CAP_RIGHTS_VERSION_00 { | ||||||
|  | 		return fmt.Errorf("bad rights version %d", capver(rights)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	n := caparsize(rights) | ||||||
|  | 	if n < capArSizeMin || n > capArSizeMax { | ||||||
|  | 		return errorspkg.New("bad rights size") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, right := range setrights { | ||||||
|  | 		if caprver(right) != CAP_RIGHTS_VERSION_00 { | ||||||
|  | 			return errorspkg.New("bad right version") | ||||||
|  | 		} | ||||||
|  | 		i, err := rightToIndex(right) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if i >= n { | ||||||
|  | 			return errorspkg.New("index overflow") | ||||||
|  | 		} | ||||||
|  | 		if capidxbit(rights.Rights[i]) != capidxbit(right) { | ||||||
|  | 			return errorspkg.New("index mismatch") | ||||||
|  | 		} | ||||||
|  | 		rights.Rights[i] |= right | ||||||
|  | 		if capidxbit(rights.Rights[i]) != capidxbit(right) { | ||||||
|  | 			return errorspkg.New("index mismatch (after assign)") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CapRightsClear clears the permissions in clearrights from rights. | ||||||
|  | func CapRightsClear(rights *CapRights, clearrights []uint64) error { | ||||||
|  | 	// This is essentially a copy of cap_rights_vclear() | ||||||
|  | 	if capver(rights) != CAP_RIGHTS_VERSION_00 { | ||||||
|  | 		return fmt.Errorf("bad rights version %d", capver(rights)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	n := caparsize(rights) | ||||||
|  | 	if n < capArSizeMin || n > capArSizeMax { | ||||||
|  | 		return errorspkg.New("bad rights size") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, right := range clearrights { | ||||||
|  | 		if caprver(right) != CAP_RIGHTS_VERSION_00 { | ||||||
|  | 			return errorspkg.New("bad right version") | ||||||
|  | 		} | ||||||
|  | 		i, err := rightToIndex(right) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if i >= n { | ||||||
|  | 			return errorspkg.New("index overflow") | ||||||
|  | 		} | ||||||
|  | 		if capidxbit(rights.Rights[i]) != capidxbit(right) { | ||||||
|  | 			return errorspkg.New("index mismatch") | ||||||
|  | 		} | ||||||
|  | 		rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF) | ||||||
|  | 		if capidxbit(rights.Rights[i]) != capidxbit(right) { | ||||||
|  | 			return errorspkg.New("index mismatch (after assign)") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CapRightsIsSet checks whether all the permissions in setrights are present in rights. | ||||||
|  | func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) { | ||||||
|  | 	// This is essentially a copy of cap_rights_is_vset() | ||||||
|  | 	if capver(rights) != CAP_RIGHTS_VERSION_00 { | ||||||
|  | 		return false, fmt.Errorf("bad rights version %d", capver(rights)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	n := caparsize(rights) | ||||||
|  | 	if n < capArSizeMin || n > capArSizeMax { | ||||||
|  | 		return false, errorspkg.New("bad rights size") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, right := range setrights { | ||||||
|  | 		if caprver(right) != CAP_RIGHTS_VERSION_00 { | ||||||
|  | 			return false, errorspkg.New("bad right version") | ||||||
|  | 		} | ||||||
|  | 		i, err := rightToIndex(right) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, err | ||||||
|  | 		} | ||||||
|  | 		if i >= n { | ||||||
|  | 			return false, errorspkg.New("index overflow") | ||||||
|  | 		} | ||||||
|  | 		if capidxbit(rights.Rights[i]) != capidxbit(right) { | ||||||
|  | 			return false, errorspkg.New("index mismatch") | ||||||
|  | 		} | ||||||
|  | 		if (rights.Rights[i] & right) != right { | ||||||
|  | 			return false, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return true, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func capright(idx uint64, bit uint64) uint64 { | ||||||
|  | 	return ((1 << (57 + idx)) | bit) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CapRightsInit returns a pointer to an initialised CapRights structure filled with rights. | ||||||
|  | // See man cap_rights_init(3) and rights(4). | ||||||
|  | func CapRightsInit(rights []uint64) (*CapRights, error) { | ||||||
|  | 	var r CapRights | ||||||
|  | 	r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0) | ||||||
|  | 	r.Rights[1] = capright(1, 0) | ||||||
|  |  | ||||||
|  | 	err := CapRightsSet(&r, rights) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &r, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CapRightsLimit reduces the operations permitted on fd to at most those contained in rights. | ||||||
|  | // The capability rights on fd can never be increased by CapRightsLimit. | ||||||
|  | // See man cap_rights_limit(2) and rights(4). | ||||||
|  | func CapRightsLimit(fd uintptr, rights *CapRights) error { | ||||||
|  | 	return capRightsLimit(int(fd), rights) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CapRightsGet returns a CapRights structure containing the operations permitted on fd. | ||||||
|  | // See man cap_rights_get(3) and rights(4). | ||||||
|  | func CapRightsGet(fd uintptr) (*CapRights, error) { | ||||||
|  | 	r, err := CapRightsInit(nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	err = capRightsGet(capRightsGoVersion, int(fd), r) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return r, nil | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								vendor/golang.org/x/sys/unix/dev_darwin.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/golang.org/x/sys/unix/dev_darwin.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // Functions to access/create device major and minor numbers matching the | ||||||
|  | // encoding used in Darwin's sys/types.h header. | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | // Major returns the major component of a Darwin device number. | ||||||
|  | func Major(dev uint64) uint32 { | ||||||
|  | 	return uint32((dev >> 24) & 0xff) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Minor returns the minor component of a Darwin device number. | ||||||
|  | func Minor(dev uint64) uint32 { | ||||||
|  | 	return uint32(dev & 0xffffff) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Mkdev returns a Darwin device number generated from the given major and minor | ||||||
|  | // components. | ||||||
|  | func Mkdev(major, minor uint32) uint64 { | ||||||
|  | 	return (uint64(major) << 24) | uint64(minor) | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								vendor/golang.org/x/sys/unix/dev_dragonfly.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								vendor/golang.org/x/sys/unix/dev_dragonfly.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // Functions to access/create device major and minor numbers matching the | ||||||
|  | // encoding used in Dragonfly's sys/types.h header. | ||||||
|  | // | ||||||
|  | // The information below is extracted and adapted from sys/types.h: | ||||||
|  | // | ||||||
|  | // Minor gives a cookie instead of an index since in order to avoid changing the | ||||||
|  | // meanings of bits 0-15 or wasting time and space shifting bits 16-31 for | ||||||
|  | // devices that don't use them. | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | // Major returns the major component of a DragonFlyBSD device number. | ||||||
|  | func Major(dev uint64) uint32 { | ||||||
|  | 	return uint32((dev >> 8) & 0xff) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Minor returns the minor component of a DragonFlyBSD device number. | ||||||
|  | func Minor(dev uint64) uint32 { | ||||||
|  | 	return uint32(dev & 0xffff00ff) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Mkdev returns a DragonFlyBSD device number generated from the given major and | ||||||
|  | // minor components. | ||||||
|  | func Mkdev(major, minor uint32) uint64 { | ||||||
|  | 	return (uint64(major) << 8) | uint64(minor) | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								vendor/golang.org/x/sys/unix/dev_freebsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								vendor/golang.org/x/sys/unix/dev_freebsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // Functions to access/create device major and minor numbers matching the | ||||||
|  | // encoding used in FreeBSD's sys/types.h header. | ||||||
|  | // | ||||||
|  | // The information below is extracted and adapted from sys/types.h: | ||||||
|  | // | ||||||
|  | // Minor gives a cookie instead of an index since in order to avoid changing the | ||||||
|  | // meanings of bits 0-15 or wasting time and space shifting bits 16-31 for | ||||||
|  | // devices that don't use them. | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | // Major returns the major component of a FreeBSD device number. | ||||||
|  | func Major(dev uint64) uint32 { | ||||||
|  | 	return uint32((dev >> 8) & 0xff) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Minor returns the minor component of a FreeBSD device number. | ||||||
|  | func Minor(dev uint64) uint32 { | ||||||
|  | 	return uint32(dev & 0xffff00ff) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Mkdev returns a FreeBSD device number generated from the given major and | ||||||
|  | // minor components. | ||||||
|  | func Mkdev(major, minor uint32) uint64 { | ||||||
|  | 	return (uint64(major) << 8) | uint64(minor) | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								vendor/golang.org/x/sys/unix/dev_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/golang.org/x/sys/unix/dev_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // Functions to access/create device major and minor numbers matching the | ||||||
|  | // encoding used by the Linux kernel and glibc. | ||||||
|  | // | ||||||
|  | // The information below is extracted and adapted from bits/sysmacros.h in the | ||||||
|  | // glibc sources: | ||||||
|  | // | ||||||
|  | // dev_t in glibc is 64-bit, with 32-bit major and minor numbers. glibc's | ||||||
|  | // default encoding is MMMM Mmmm mmmM MMmm, where M is a hex digit of the major | ||||||
|  | // number and m is a hex digit of the minor number. This is backward compatible | ||||||
|  | // with legacy systems where dev_t is 16 bits wide, encoded as MMmm. It is also | ||||||
|  | // backward compatible with the Linux kernel, which for some architectures uses | ||||||
|  | // 32-bit dev_t, encoded as mmmM MMmm. | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | // Major returns the major component of a Linux device number. | ||||||
|  | func Major(dev uint64) uint32 { | ||||||
|  | 	major := uint32((dev & 0x00000000000fff00) >> 8) | ||||||
|  | 	major |= uint32((dev & 0xfffff00000000000) >> 32) | ||||||
|  | 	return major | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Minor returns the minor component of a Linux device number. | ||||||
|  | func Minor(dev uint64) uint32 { | ||||||
|  | 	minor := uint32((dev & 0x00000000000000ff) >> 0) | ||||||
|  | 	minor |= uint32((dev & 0x00000ffffff00000) >> 12) | ||||||
|  | 	return minor | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Mkdev returns a Linux device number generated from the given major and minor | ||||||
|  | // components. | ||||||
|  | func Mkdev(major, minor uint32) uint64 { | ||||||
|  | 	dev := (uint64(major) & 0x00000fff) << 8 | ||||||
|  | 	dev |= (uint64(major) & 0xfffff000) << 32 | ||||||
|  | 	dev |= (uint64(minor) & 0x000000ff) << 0 | ||||||
|  | 	dev |= (uint64(minor) & 0xffffff00) << 12 | ||||||
|  | 	return dev | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								vendor/golang.org/x/sys/unix/dev_netbsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/golang.org/x/sys/unix/dev_netbsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // Functions to access/create device major and minor numbers matching the | ||||||
|  | // encoding used in NetBSD's sys/types.h header. | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | // Major returns the major component of a NetBSD device number. | ||||||
|  | func Major(dev uint64) uint32 { | ||||||
|  | 	return uint32((dev & 0x000fff00) >> 8) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Minor returns the minor component of a NetBSD device number. | ||||||
|  | func Minor(dev uint64) uint32 { | ||||||
|  | 	minor := uint32((dev & 0x000000ff) >> 0) | ||||||
|  | 	minor |= uint32((dev & 0xfff00000) >> 12) | ||||||
|  | 	return minor | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Mkdev returns a NetBSD device number generated from the given major and minor | ||||||
|  | // components. | ||||||
|  | func Mkdev(major, minor uint32) uint64 { | ||||||
|  | 	dev := (uint64(major) << 8) & 0x000fff00 | ||||||
|  | 	dev |= (uint64(minor) << 12) & 0xfff00000 | ||||||
|  | 	dev |= (uint64(minor) << 0) & 0x000000ff | ||||||
|  | 	return dev | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								vendor/golang.org/x/sys/unix/dev_openbsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/golang.org/x/sys/unix/dev_openbsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // Functions to access/create device major and minor numbers matching the | ||||||
|  | // encoding used in OpenBSD's sys/types.h header. | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | // Major returns the major component of an OpenBSD device number. | ||||||
|  | func Major(dev uint64) uint32 { | ||||||
|  | 	return uint32((dev & 0x0000ff00) >> 8) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Minor returns the minor component of an OpenBSD device number. | ||||||
|  | func Minor(dev uint64) uint32 { | ||||||
|  | 	minor := uint32((dev & 0x000000ff) >> 0) | ||||||
|  | 	minor |= uint32((dev & 0xffff0000) >> 8) | ||||||
|  | 	return minor | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Mkdev returns an OpenBSD device number generated from the given major and minor | ||||||
|  | // components. | ||||||
|  | func Mkdev(major, minor uint32) uint64 { | ||||||
|  | 	dev := (uint64(major) << 8) & 0x0000ff00 | ||||||
|  | 	dev |= (uint64(minor) << 8) & 0xffff0000 | ||||||
|  | 	dev |= (uint64(minor) << 0) & 0x000000ff | ||||||
|  | 	return dev | ||||||
|  | } | ||||||
							
								
								
									
										102
									
								
								vendor/golang.org/x/sys/unix/dirent.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								vendor/golang.org/x/sys/unix/dirent.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | |||||||
|  | // Copyright 2009 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. | ||||||
|  |  | ||||||
|  | // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | import "unsafe" | ||||||
|  |  | ||||||
|  | // readInt returns the size-bytes unsigned integer in native byte order at offset off. | ||||||
|  | func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { | ||||||
|  | 	if len(b) < int(off+size) { | ||||||
|  | 		return 0, false | ||||||
|  | 	} | ||||||
|  | 	if isBigEndian { | ||||||
|  | 		return readIntBE(b[off:], size), true | ||||||
|  | 	} | ||||||
|  | 	return readIntLE(b[off:], size), true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func readIntBE(b []byte, size uintptr) uint64 { | ||||||
|  | 	switch size { | ||||||
|  | 	case 1: | ||||||
|  | 		return uint64(b[0]) | ||||||
|  | 	case 2: | ||||||
|  | 		_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 | ||||||
|  | 		return uint64(b[1]) | uint64(b[0])<<8 | ||||||
|  | 	case 4: | ||||||
|  | 		_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 | ||||||
|  | 		return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24 | ||||||
|  | 	case 8: | ||||||
|  | 		_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 | ||||||
|  | 		return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | | ||||||
|  | 			uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 | ||||||
|  | 	default: | ||||||
|  | 		panic("syscall: readInt with unsupported size") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func readIntLE(b []byte, size uintptr) uint64 { | ||||||
|  | 	switch size { | ||||||
|  | 	case 1: | ||||||
|  | 		return uint64(b[0]) | ||||||
|  | 	case 2: | ||||||
|  | 		_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 | ||||||
|  | 		return uint64(b[0]) | uint64(b[1])<<8 | ||||||
|  | 	case 4: | ||||||
|  | 		_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 | ||||||
|  | 		return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | ||||||
|  | 	case 8: | ||||||
|  | 		_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 | ||||||
|  | 		return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | | ||||||
|  | 			uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 | ||||||
|  | 	default: | ||||||
|  | 		panic("syscall: readInt with unsupported size") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ParseDirent parses up to max directory entries in buf, | ||||||
|  | // appending the names to names. It returns the number of | ||||||
|  | // bytes consumed from buf, the number of entries added | ||||||
|  | // to names, and the new names slice. | ||||||
|  | func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { | ||||||
|  | 	origlen := len(buf) | ||||||
|  | 	count = 0 | ||||||
|  | 	for max != 0 && len(buf) > 0 { | ||||||
|  | 		reclen, ok := direntReclen(buf) | ||||||
|  | 		if !ok || reclen > uint64(len(buf)) { | ||||||
|  | 			return origlen, count, names | ||||||
|  | 		} | ||||||
|  | 		rec := buf[:reclen] | ||||||
|  | 		buf = buf[reclen:] | ||||||
|  | 		ino, ok := direntIno(rec) | ||||||
|  | 		if !ok { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		if ino == 0 { // File absent in directory. | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		const namoff = uint64(unsafe.Offsetof(Dirent{}.Name)) | ||||||
|  | 		namlen, ok := direntNamlen(rec) | ||||||
|  | 		if !ok || namoff+namlen > uint64(len(rec)) { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		name := rec[namoff : namoff+namlen] | ||||||
|  | 		for i, c := range name { | ||||||
|  | 			if c == 0 { | ||||||
|  | 				name = name[:i] | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		// Check for useless names before allocating a string. | ||||||
|  | 		if string(name) == "." || string(name) == ".." { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		max-- | ||||||
|  | 		count++ | ||||||
|  | 		names = append(names, string(name)) | ||||||
|  | 	} | ||||||
|  | 	return origlen - len(buf), count, names | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								vendor/golang.org/x/sys/unix/endian_big.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/golang.org/x/sys/unix/endian_big.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | // Copyright 2016 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. | ||||||
|  | // | ||||||
|  | // +build ppc64 s390x mips mips64 | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | const isBigEndian = true | ||||||
							
								
								
									
										9
									
								
								vendor/golang.org/x/sys/unix/endian_little.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/golang.org/x/sys/unix/endian_little.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | // Copyright 2016 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. | ||||||
|  | // | ||||||
|  | // +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | const isBigEndian = false | ||||||
							
								
								
									
										227
									
								
								vendor/golang.org/x/sys/unix/errors_freebsd_386.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								vendor/golang.org/x/sys/unix/errors_freebsd_386.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // Constants that were deprecated or moved to enums in the FreeBSD headers. Keep | ||||||
|  | // them here for backwards compatibility. | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	IFF_SMART                         = 0x20 | ||||||
|  | 	IFT_1822                          = 0x2 | ||||||
|  | 	IFT_A12MPPSWITCH                  = 0x82 | ||||||
|  | 	IFT_AAL2                          = 0xbb | ||||||
|  | 	IFT_AAL5                          = 0x31 | ||||||
|  | 	IFT_ADSL                          = 0x5e | ||||||
|  | 	IFT_AFLANE8023                    = 0x3b | ||||||
|  | 	IFT_AFLANE8025                    = 0x3c | ||||||
|  | 	IFT_ARAP                          = 0x58 | ||||||
|  | 	IFT_ARCNET                        = 0x23 | ||||||
|  | 	IFT_ARCNETPLUS                    = 0x24 | ||||||
|  | 	IFT_ASYNC                         = 0x54 | ||||||
|  | 	IFT_ATM                           = 0x25 | ||||||
|  | 	IFT_ATMDXI                        = 0x69 | ||||||
|  | 	IFT_ATMFUNI                       = 0x6a | ||||||
|  | 	IFT_ATMIMA                        = 0x6b | ||||||
|  | 	IFT_ATMLOGICAL                    = 0x50 | ||||||
|  | 	IFT_ATMRADIO                      = 0xbd | ||||||
|  | 	IFT_ATMSUBINTERFACE               = 0x86 | ||||||
|  | 	IFT_ATMVCIENDPT                   = 0xc2 | ||||||
|  | 	IFT_ATMVIRTUAL                    = 0x95 | ||||||
|  | 	IFT_BGPPOLICYACCOUNTING           = 0xa2 | ||||||
|  | 	IFT_BSC                           = 0x53 | ||||||
|  | 	IFT_CCTEMUL                       = 0x3d | ||||||
|  | 	IFT_CEPT                          = 0x13 | ||||||
|  | 	IFT_CES                           = 0x85 | ||||||
|  | 	IFT_CHANNEL                       = 0x46 | ||||||
|  | 	IFT_CNR                           = 0x55 | ||||||
|  | 	IFT_COFFEE                        = 0x84 | ||||||
|  | 	IFT_COMPOSITELINK                 = 0x9b | ||||||
|  | 	IFT_DCN                           = 0x8d | ||||||
|  | 	IFT_DIGITALPOWERLINE              = 0x8a | ||||||
|  | 	IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba | ||||||
|  | 	IFT_DLSW                          = 0x4a | ||||||
|  | 	IFT_DOCSCABLEDOWNSTREAM           = 0x80 | ||||||
|  | 	IFT_DOCSCABLEMACLAYER             = 0x7f | ||||||
|  | 	IFT_DOCSCABLEUPSTREAM             = 0x81 | ||||||
|  | 	IFT_DS0                           = 0x51 | ||||||
|  | 	IFT_DS0BUNDLE                     = 0x52 | ||||||
|  | 	IFT_DS1FDL                        = 0xaa | ||||||
|  | 	IFT_DS3                           = 0x1e | ||||||
|  | 	IFT_DTM                           = 0x8c | ||||||
|  | 	IFT_DVBASILN                      = 0xac | ||||||
|  | 	IFT_DVBASIOUT                     = 0xad | ||||||
|  | 	IFT_DVBRCCDOWNSTREAM              = 0x93 | ||||||
|  | 	IFT_DVBRCCMACLAYER                = 0x92 | ||||||
|  | 	IFT_DVBRCCUPSTREAM                = 0x94 | ||||||
|  | 	IFT_ENC                           = 0xf4 | ||||||
|  | 	IFT_EON                           = 0x19 | ||||||
|  | 	IFT_EPLRS                         = 0x57 | ||||||
|  | 	IFT_ESCON                         = 0x49 | ||||||
|  | 	IFT_ETHER                         = 0x6 | ||||||
|  | 	IFT_FAITH                         = 0xf2 | ||||||
|  | 	IFT_FAST                          = 0x7d | ||||||
|  | 	IFT_FASTETHER                     = 0x3e | ||||||
|  | 	IFT_FASTETHERFX                   = 0x45 | ||||||
|  | 	IFT_FDDI                          = 0xf | ||||||
|  | 	IFT_FIBRECHANNEL                  = 0x38 | ||||||
|  | 	IFT_FRAMERELAYINTERCONNECT        = 0x3a | ||||||
|  | 	IFT_FRAMERELAYMPI                 = 0x5c | ||||||
|  | 	IFT_FRDLCIENDPT                   = 0xc1 | ||||||
|  | 	IFT_FRELAY                        = 0x20 | ||||||
|  | 	IFT_FRELAYDCE                     = 0x2c | ||||||
|  | 	IFT_FRF16MFRBUNDLE                = 0xa3 | ||||||
|  | 	IFT_FRFORWARD                     = 0x9e | ||||||
|  | 	IFT_G703AT2MB                     = 0x43 | ||||||
|  | 	IFT_G703AT64K                     = 0x42 | ||||||
|  | 	IFT_GIF                           = 0xf0 | ||||||
|  | 	IFT_GIGABITETHERNET               = 0x75 | ||||||
|  | 	IFT_GR303IDT                      = 0xb2 | ||||||
|  | 	IFT_GR303RDT                      = 0xb1 | ||||||
|  | 	IFT_H323GATEKEEPER                = 0xa4 | ||||||
|  | 	IFT_H323PROXY                     = 0xa5 | ||||||
|  | 	IFT_HDH1822                       = 0x3 | ||||||
|  | 	IFT_HDLC                          = 0x76 | ||||||
|  | 	IFT_HDSL2                         = 0xa8 | ||||||
|  | 	IFT_HIPERLAN2                     = 0xb7 | ||||||
|  | 	IFT_HIPPI                         = 0x2f | ||||||
|  | 	IFT_HIPPIINTERFACE                = 0x39 | ||||||
|  | 	IFT_HOSTPAD                       = 0x5a | ||||||
|  | 	IFT_HSSI                          = 0x2e | ||||||
|  | 	IFT_HY                            = 0xe | ||||||
|  | 	IFT_IBM370PARCHAN                 = 0x48 | ||||||
|  | 	IFT_IDSL                          = 0x9a | ||||||
|  | 	IFT_IEEE80211                     = 0x47 | ||||||
|  | 	IFT_IEEE80212                     = 0x37 | ||||||
|  | 	IFT_IEEE8023ADLAG                 = 0xa1 | ||||||
|  | 	IFT_IFGSN                         = 0x91 | ||||||
|  | 	IFT_IMT                           = 0xbe | ||||||
|  | 	IFT_INTERLEAVE                    = 0x7c | ||||||
|  | 	IFT_IP                            = 0x7e | ||||||
|  | 	IFT_IPFORWARD                     = 0x8e | ||||||
|  | 	IFT_IPOVERATM                     = 0x72 | ||||||
|  | 	IFT_IPOVERCDLC                    = 0x6d | ||||||
|  | 	IFT_IPOVERCLAW                    = 0x6e | ||||||
|  | 	IFT_IPSWITCH                      = 0x4e | ||||||
|  | 	IFT_IPXIP                         = 0xf9 | ||||||
|  | 	IFT_ISDN                          = 0x3f | ||||||
|  | 	IFT_ISDNBASIC                     = 0x14 | ||||||
|  | 	IFT_ISDNPRIMARY                   = 0x15 | ||||||
|  | 	IFT_ISDNS                         = 0x4b | ||||||
|  | 	IFT_ISDNU                         = 0x4c | ||||||
|  | 	IFT_ISO88022LLC                   = 0x29 | ||||||
|  | 	IFT_ISO88023                      = 0x7 | ||||||
|  | 	IFT_ISO88024                      = 0x8 | ||||||
|  | 	IFT_ISO88025                      = 0x9 | ||||||
|  | 	IFT_ISO88025CRFPINT               = 0x62 | ||||||
|  | 	IFT_ISO88025DTR                   = 0x56 | ||||||
|  | 	IFT_ISO88025FIBER                 = 0x73 | ||||||
|  | 	IFT_ISO88026                      = 0xa | ||||||
|  | 	IFT_ISUP                          = 0xb3 | ||||||
|  | 	IFT_L3IPXVLAN                     = 0x89 | ||||||
|  | 	IFT_LAPB                          = 0x10 | ||||||
|  | 	IFT_LAPD                          = 0x4d | ||||||
|  | 	IFT_LAPF                          = 0x77 | ||||||
|  | 	IFT_LOCALTALK                     = 0x2a | ||||||
|  | 	IFT_LOOP                          = 0x18 | ||||||
|  | 	IFT_MEDIAMAILOVERIP               = 0x8b | ||||||
|  | 	IFT_MFSIGLINK                     = 0xa7 | ||||||
|  | 	IFT_MIOX25                        = 0x26 | ||||||
|  | 	IFT_MODEM                         = 0x30 | ||||||
|  | 	IFT_MPC                           = 0x71 | ||||||
|  | 	IFT_MPLS                          = 0xa6 | ||||||
|  | 	IFT_MPLSTUNNEL                    = 0x96 | ||||||
|  | 	IFT_MSDSL                         = 0x8f | ||||||
|  | 	IFT_MVL                           = 0xbf | ||||||
|  | 	IFT_MYRINET                       = 0x63 | ||||||
|  | 	IFT_NFAS                          = 0xaf | ||||||
|  | 	IFT_NSIP                          = 0x1b | ||||||
|  | 	IFT_OPTICALCHANNEL                = 0xc3 | ||||||
|  | 	IFT_OPTICALTRANSPORT              = 0xc4 | ||||||
|  | 	IFT_OTHER                         = 0x1 | ||||||
|  | 	IFT_P10                           = 0xc | ||||||
|  | 	IFT_P80                           = 0xd | ||||||
|  | 	IFT_PARA                          = 0x22 | ||||||
|  | 	IFT_PFLOG                         = 0xf6 | ||||||
|  | 	IFT_PFSYNC                        = 0xf7 | ||||||
|  | 	IFT_PLC                           = 0xae | ||||||
|  | 	IFT_POS                           = 0xab | ||||||
|  | 	IFT_PPPMULTILINKBUNDLE            = 0x6c | ||||||
|  | 	IFT_PROPBWAP2MP                   = 0xb8 | ||||||
|  | 	IFT_PROPCNLS                      = 0x59 | ||||||
|  | 	IFT_PROPDOCSWIRELESSDOWNSTREAM    = 0xb5 | ||||||
|  | 	IFT_PROPDOCSWIRELESSMACLAYER      = 0xb4 | ||||||
|  | 	IFT_PROPDOCSWIRELESSUPSTREAM      = 0xb6 | ||||||
|  | 	IFT_PROPMUX                       = 0x36 | ||||||
|  | 	IFT_PROPWIRELESSP2P               = 0x9d | ||||||
|  | 	IFT_PTPSERIAL                     = 0x16 | ||||||
|  | 	IFT_PVC                           = 0xf1 | ||||||
|  | 	IFT_QLLC                          = 0x44 | ||||||
|  | 	IFT_RADIOMAC                      = 0xbc | ||||||
|  | 	IFT_RADSL                         = 0x5f | ||||||
|  | 	IFT_REACHDSL                      = 0xc0 | ||||||
|  | 	IFT_RFC1483                       = 0x9f | ||||||
|  | 	IFT_RS232                         = 0x21 | ||||||
|  | 	IFT_RSRB                          = 0x4f | ||||||
|  | 	IFT_SDLC                          = 0x11 | ||||||
|  | 	IFT_SDSL                          = 0x60 | ||||||
|  | 	IFT_SHDSL                         = 0xa9 | ||||||
|  | 	IFT_SIP                           = 0x1f | ||||||
|  | 	IFT_SLIP                          = 0x1c | ||||||
|  | 	IFT_SMDSDXI                       = 0x2b | ||||||
|  | 	IFT_SMDSICIP                      = 0x34 | ||||||
|  | 	IFT_SONET                         = 0x27 | ||||||
|  | 	IFT_SONETOVERHEADCHANNEL          = 0xb9 | ||||||
|  | 	IFT_SONETPATH                     = 0x32 | ||||||
|  | 	IFT_SONETVT                       = 0x33 | ||||||
|  | 	IFT_SRP                           = 0x97 | ||||||
|  | 	IFT_SS7SIGLINK                    = 0x9c | ||||||
|  | 	IFT_STACKTOSTACK                  = 0x6f | ||||||
|  | 	IFT_STARLAN                       = 0xb | ||||||
|  | 	IFT_STF                           = 0xd7 | ||||||
|  | 	IFT_T1                            = 0x12 | ||||||
|  | 	IFT_TDLC                          = 0x74 | ||||||
|  | 	IFT_TERMPAD                       = 0x5b | ||||||
|  | 	IFT_TR008                         = 0xb0 | ||||||
|  | 	IFT_TRANSPHDLC                    = 0x7b | ||||||
|  | 	IFT_TUNNEL                        = 0x83 | ||||||
|  | 	IFT_ULTRA                         = 0x1d | ||||||
|  | 	IFT_USB                           = 0xa0 | ||||||
|  | 	IFT_V11                           = 0x40 | ||||||
|  | 	IFT_V35                           = 0x2d | ||||||
|  | 	IFT_V36                           = 0x41 | ||||||
|  | 	IFT_V37                           = 0x78 | ||||||
|  | 	IFT_VDSL                          = 0x61 | ||||||
|  | 	IFT_VIRTUALIPADDRESS              = 0x70 | ||||||
|  | 	IFT_VOICEEM                       = 0x64 | ||||||
|  | 	IFT_VOICEENCAP                    = 0x67 | ||||||
|  | 	IFT_VOICEFXO                      = 0x65 | ||||||
|  | 	IFT_VOICEFXS                      = 0x66 | ||||||
|  | 	IFT_VOICEOVERATM                  = 0x98 | ||||||
|  | 	IFT_VOICEOVERFRAMERELAY           = 0x99 | ||||||
|  | 	IFT_VOICEOVERIP                   = 0x68 | ||||||
|  | 	IFT_X213                          = 0x5d | ||||||
|  | 	IFT_X25                           = 0x5 | ||||||
|  | 	IFT_X25DDN                        = 0x4 | ||||||
|  | 	IFT_X25HUNTGROUP                  = 0x7a | ||||||
|  | 	IFT_X25MLP                        = 0x79 | ||||||
|  | 	IFT_X25PLE                        = 0x28 | ||||||
|  | 	IFT_XETHER                        = 0x1a | ||||||
|  | 	IPPROTO_MAXID                     = 0x34 | ||||||
|  | 	IPV6_FAITH                        = 0x1d | ||||||
|  | 	IP_FAITH                          = 0x16 | ||||||
|  | 	MAP_NORESERVE                     = 0x40 | ||||||
|  | 	MAP_RENAME                        = 0x20 | ||||||
|  | 	NET_RT_MAXID                      = 0x6 | ||||||
|  | 	RTF_PRCLONING                     = 0x10000 | ||||||
|  | 	RTM_OLDADD                        = 0x9 | ||||||
|  | 	RTM_OLDDEL                        = 0xa | ||||||
|  | 	SIOCADDRT                         = 0x8030720a | ||||||
|  | 	SIOCALIFADDR                      = 0x8118691b | ||||||
|  | 	SIOCDELRT                         = 0x8030720b | ||||||
|  | 	SIOCDLIFADDR                      = 0x8118691d | ||||||
|  | 	SIOCGLIFADDR                      = 0xc118691c | ||||||
|  | 	SIOCGLIFPHYADDR                   = 0xc118694b | ||||||
|  | 	SIOCSLIFPHYADDR                   = 0x8118694a | ||||||
|  | ) | ||||||
							
								
								
									
										227
									
								
								vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								vendor/golang.org/x/sys/unix/errors_freebsd_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // Constants that were deprecated or moved to enums in the FreeBSD headers. Keep | ||||||
|  | // them here for backwards compatibility. | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	IFF_SMART                         = 0x20 | ||||||
|  | 	IFT_1822                          = 0x2 | ||||||
|  | 	IFT_A12MPPSWITCH                  = 0x82 | ||||||
|  | 	IFT_AAL2                          = 0xbb | ||||||
|  | 	IFT_AAL5                          = 0x31 | ||||||
|  | 	IFT_ADSL                          = 0x5e | ||||||
|  | 	IFT_AFLANE8023                    = 0x3b | ||||||
|  | 	IFT_AFLANE8025                    = 0x3c | ||||||
|  | 	IFT_ARAP                          = 0x58 | ||||||
|  | 	IFT_ARCNET                        = 0x23 | ||||||
|  | 	IFT_ARCNETPLUS                    = 0x24 | ||||||
|  | 	IFT_ASYNC                         = 0x54 | ||||||
|  | 	IFT_ATM                           = 0x25 | ||||||
|  | 	IFT_ATMDXI                        = 0x69 | ||||||
|  | 	IFT_ATMFUNI                       = 0x6a | ||||||
|  | 	IFT_ATMIMA                        = 0x6b | ||||||
|  | 	IFT_ATMLOGICAL                    = 0x50 | ||||||
|  | 	IFT_ATMRADIO                      = 0xbd | ||||||
|  | 	IFT_ATMSUBINTERFACE               = 0x86 | ||||||
|  | 	IFT_ATMVCIENDPT                   = 0xc2 | ||||||
|  | 	IFT_ATMVIRTUAL                    = 0x95 | ||||||
|  | 	IFT_BGPPOLICYACCOUNTING           = 0xa2 | ||||||
|  | 	IFT_BSC                           = 0x53 | ||||||
|  | 	IFT_CCTEMUL                       = 0x3d | ||||||
|  | 	IFT_CEPT                          = 0x13 | ||||||
|  | 	IFT_CES                           = 0x85 | ||||||
|  | 	IFT_CHANNEL                       = 0x46 | ||||||
|  | 	IFT_CNR                           = 0x55 | ||||||
|  | 	IFT_COFFEE                        = 0x84 | ||||||
|  | 	IFT_COMPOSITELINK                 = 0x9b | ||||||
|  | 	IFT_DCN                           = 0x8d | ||||||
|  | 	IFT_DIGITALPOWERLINE              = 0x8a | ||||||
|  | 	IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba | ||||||
|  | 	IFT_DLSW                          = 0x4a | ||||||
|  | 	IFT_DOCSCABLEDOWNSTREAM           = 0x80 | ||||||
|  | 	IFT_DOCSCABLEMACLAYER             = 0x7f | ||||||
|  | 	IFT_DOCSCABLEUPSTREAM             = 0x81 | ||||||
|  | 	IFT_DS0                           = 0x51 | ||||||
|  | 	IFT_DS0BUNDLE                     = 0x52 | ||||||
|  | 	IFT_DS1FDL                        = 0xaa | ||||||
|  | 	IFT_DS3                           = 0x1e | ||||||
|  | 	IFT_DTM                           = 0x8c | ||||||
|  | 	IFT_DVBASILN                      = 0xac | ||||||
|  | 	IFT_DVBASIOUT                     = 0xad | ||||||
|  | 	IFT_DVBRCCDOWNSTREAM              = 0x93 | ||||||
|  | 	IFT_DVBRCCMACLAYER                = 0x92 | ||||||
|  | 	IFT_DVBRCCUPSTREAM                = 0x94 | ||||||
|  | 	IFT_ENC                           = 0xf4 | ||||||
|  | 	IFT_EON                           = 0x19 | ||||||
|  | 	IFT_EPLRS                         = 0x57 | ||||||
|  | 	IFT_ESCON                         = 0x49 | ||||||
|  | 	IFT_ETHER                         = 0x6 | ||||||
|  | 	IFT_FAITH                         = 0xf2 | ||||||
|  | 	IFT_FAST                          = 0x7d | ||||||
|  | 	IFT_FASTETHER                     = 0x3e | ||||||
|  | 	IFT_FASTETHERFX                   = 0x45 | ||||||
|  | 	IFT_FDDI                          = 0xf | ||||||
|  | 	IFT_FIBRECHANNEL                  = 0x38 | ||||||
|  | 	IFT_FRAMERELAYINTERCONNECT        = 0x3a | ||||||
|  | 	IFT_FRAMERELAYMPI                 = 0x5c | ||||||
|  | 	IFT_FRDLCIENDPT                   = 0xc1 | ||||||
|  | 	IFT_FRELAY                        = 0x20 | ||||||
|  | 	IFT_FRELAYDCE                     = 0x2c | ||||||
|  | 	IFT_FRF16MFRBUNDLE                = 0xa3 | ||||||
|  | 	IFT_FRFORWARD                     = 0x9e | ||||||
|  | 	IFT_G703AT2MB                     = 0x43 | ||||||
|  | 	IFT_G703AT64K                     = 0x42 | ||||||
|  | 	IFT_GIF                           = 0xf0 | ||||||
|  | 	IFT_GIGABITETHERNET               = 0x75 | ||||||
|  | 	IFT_GR303IDT                      = 0xb2 | ||||||
|  | 	IFT_GR303RDT                      = 0xb1 | ||||||
|  | 	IFT_H323GATEKEEPER                = 0xa4 | ||||||
|  | 	IFT_H323PROXY                     = 0xa5 | ||||||
|  | 	IFT_HDH1822                       = 0x3 | ||||||
|  | 	IFT_HDLC                          = 0x76 | ||||||
|  | 	IFT_HDSL2                         = 0xa8 | ||||||
|  | 	IFT_HIPERLAN2                     = 0xb7 | ||||||
|  | 	IFT_HIPPI                         = 0x2f | ||||||
|  | 	IFT_HIPPIINTERFACE                = 0x39 | ||||||
|  | 	IFT_HOSTPAD                       = 0x5a | ||||||
|  | 	IFT_HSSI                          = 0x2e | ||||||
|  | 	IFT_HY                            = 0xe | ||||||
|  | 	IFT_IBM370PARCHAN                 = 0x48 | ||||||
|  | 	IFT_IDSL                          = 0x9a | ||||||
|  | 	IFT_IEEE80211                     = 0x47 | ||||||
|  | 	IFT_IEEE80212                     = 0x37 | ||||||
|  | 	IFT_IEEE8023ADLAG                 = 0xa1 | ||||||
|  | 	IFT_IFGSN                         = 0x91 | ||||||
|  | 	IFT_IMT                           = 0xbe | ||||||
|  | 	IFT_INTERLEAVE                    = 0x7c | ||||||
|  | 	IFT_IP                            = 0x7e | ||||||
|  | 	IFT_IPFORWARD                     = 0x8e | ||||||
|  | 	IFT_IPOVERATM                     = 0x72 | ||||||
|  | 	IFT_IPOVERCDLC                    = 0x6d | ||||||
|  | 	IFT_IPOVERCLAW                    = 0x6e | ||||||
|  | 	IFT_IPSWITCH                      = 0x4e | ||||||
|  | 	IFT_IPXIP                         = 0xf9 | ||||||
|  | 	IFT_ISDN                          = 0x3f | ||||||
|  | 	IFT_ISDNBASIC                     = 0x14 | ||||||
|  | 	IFT_ISDNPRIMARY                   = 0x15 | ||||||
|  | 	IFT_ISDNS                         = 0x4b | ||||||
|  | 	IFT_ISDNU                         = 0x4c | ||||||
|  | 	IFT_ISO88022LLC                   = 0x29 | ||||||
|  | 	IFT_ISO88023                      = 0x7 | ||||||
|  | 	IFT_ISO88024                      = 0x8 | ||||||
|  | 	IFT_ISO88025                      = 0x9 | ||||||
|  | 	IFT_ISO88025CRFPINT               = 0x62 | ||||||
|  | 	IFT_ISO88025DTR                   = 0x56 | ||||||
|  | 	IFT_ISO88025FIBER                 = 0x73 | ||||||
|  | 	IFT_ISO88026                      = 0xa | ||||||
|  | 	IFT_ISUP                          = 0xb3 | ||||||
|  | 	IFT_L3IPXVLAN                     = 0x89 | ||||||
|  | 	IFT_LAPB                          = 0x10 | ||||||
|  | 	IFT_LAPD                          = 0x4d | ||||||
|  | 	IFT_LAPF                          = 0x77 | ||||||
|  | 	IFT_LOCALTALK                     = 0x2a | ||||||
|  | 	IFT_LOOP                          = 0x18 | ||||||
|  | 	IFT_MEDIAMAILOVERIP               = 0x8b | ||||||
|  | 	IFT_MFSIGLINK                     = 0xa7 | ||||||
|  | 	IFT_MIOX25                        = 0x26 | ||||||
|  | 	IFT_MODEM                         = 0x30 | ||||||
|  | 	IFT_MPC                           = 0x71 | ||||||
|  | 	IFT_MPLS                          = 0xa6 | ||||||
|  | 	IFT_MPLSTUNNEL                    = 0x96 | ||||||
|  | 	IFT_MSDSL                         = 0x8f | ||||||
|  | 	IFT_MVL                           = 0xbf | ||||||
|  | 	IFT_MYRINET                       = 0x63 | ||||||
|  | 	IFT_NFAS                          = 0xaf | ||||||
|  | 	IFT_NSIP                          = 0x1b | ||||||
|  | 	IFT_OPTICALCHANNEL                = 0xc3 | ||||||
|  | 	IFT_OPTICALTRANSPORT              = 0xc4 | ||||||
|  | 	IFT_OTHER                         = 0x1 | ||||||
|  | 	IFT_P10                           = 0xc | ||||||
|  | 	IFT_P80                           = 0xd | ||||||
|  | 	IFT_PARA                          = 0x22 | ||||||
|  | 	IFT_PFLOG                         = 0xf6 | ||||||
|  | 	IFT_PFSYNC                        = 0xf7 | ||||||
|  | 	IFT_PLC                           = 0xae | ||||||
|  | 	IFT_POS                           = 0xab | ||||||
|  | 	IFT_PPPMULTILINKBUNDLE            = 0x6c | ||||||
|  | 	IFT_PROPBWAP2MP                   = 0xb8 | ||||||
|  | 	IFT_PROPCNLS                      = 0x59 | ||||||
|  | 	IFT_PROPDOCSWIRELESSDOWNSTREAM    = 0xb5 | ||||||
|  | 	IFT_PROPDOCSWIRELESSMACLAYER      = 0xb4 | ||||||
|  | 	IFT_PROPDOCSWIRELESSUPSTREAM      = 0xb6 | ||||||
|  | 	IFT_PROPMUX                       = 0x36 | ||||||
|  | 	IFT_PROPWIRELESSP2P               = 0x9d | ||||||
|  | 	IFT_PTPSERIAL                     = 0x16 | ||||||
|  | 	IFT_PVC                           = 0xf1 | ||||||
|  | 	IFT_QLLC                          = 0x44 | ||||||
|  | 	IFT_RADIOMAC                      = 0xbc | ||||||
|  | 	IFT_RADSL                         = 0x5f | ||||||
|  | 	IFT_REACHDSL                      = 0xc0 | ||||||
|  | 	IFT_RFC1483                       = 0x9f | ||||||
|  | 	IFT_RS232                         = 0x21 | ||||||
|  | 	IFT_RSRB                          = 0x4f | ||||||
|  | 	IFT_SDLC                          = 0x11 | ||||||
|  | 	IFT_SDSL                          = 0x60 | ||||||
|  | 	IFT_SHDSL                         = 0xa9 | ||||||
|  | 	IFT_SIP                           = 0x1f | ||||||
|  | 	IFT_SLIP                          = 0x1c | ||||||
|  | 	IFT_SMDSDXI                       = 0x2b | ||||||
|  | 	IFT_SMDSICIP                      = 0x34 | ||||||
|  | 	IFT_SONET                         = 0x27 | ||||||
|  | 	IFT_SONETOVERHEADCHANNEL          = 0xb9 | ||||||
|  | 	IFT_SONETPATH                     = 0x32 | ||||||
|  | 	IFT_SONETVT                       = 0x33 | ||||||
|  | 	IFT_SRP                           = 0x97 | ||||||
|  | 	IFT_SS7SIGLINK                    = 0x9c | ||||||
|  | 	IFT_STACKTOSTACK                  = 0x6f | ||||||
|  | 	IFT_STARLAN                       = 0xb | ||||||
|  | 	IFT_STF                           = 0xd7 | ||||||
|  | 	IFT_T1                            = 0x12 | ||||||
|  | 	IFT_TDLC                          = 0x74 | ||||||
|  | 	IFT_TERMPAD                       = 0x5b | ||||||
|  | 	IFT_TR008                         = 0xb0 | ||||||
|  | 	IFT_TRANSPHDLC                    = 0x7b | ||||||
|  | 	IFT_TUNNEL                        = 0x83 | ||||||
|  | 	IFT_ULTRA                         = 0x1d | ||||||
|  | 	IFT_USB                           = 0xa0 | ||||||
|  | 	IFT_V11                           = 0x40 | ||||||
|  | 	IFT_V35                           = 0x2d | ||||||
|  | 	IFT_V36                           = 0x41 | ||||||
|  | 	IFT_V37                           = 0x78 | ||||||
|  | 	IFT_VDSL                          = 0x61 | ||||||
|  | 	IFT_VIRTUALIPADDRESS              = 0x70 | ||||||
|  | 	IFT_VOICEEM                       = 0x64 | ||||||
|  | 	IFT_VOICEENCAP                    = 0x67 | ||||||
|  | 	IFT_VOICEFXO                      = 0x65 | ||||||
|  | 	IFT_VOICEFXS                      = 0x66 | ||||||
|  | 	IFT_VOICEOVERATM                  = 0x98 | ||||||
|  | 	IFT_VOICEOVERFRAMERELAY           = 0x99 | ||||||
|  | 	IFT_VOICEOVERIP                   = 0x68 | ||||||
|  | 	IFT_X213                          = 0x5d | ||||||
|  | 	IFT_X25                           = 0x5 | ||||||
|  | 	IFT_X25DDN                        = 0x4 | ||||||
|  | 	IFT_X25HUNTGROUP                  = 0x7a | ||||||
|  | 	IFT_X25MLP                        = 0x79 | ||||||
|  | 	IFT_X25PLE                        = 0x28 | ||||||
|  | 	IFT_XETHER                        = 0x1a | ||||||
|  | 	IPPROTO_MAXID                     = 0x34 | ||||||
|  | 	IPV6_FAITH                        = 0x1d | ||||||
|  | 	IP_FAITH                          = 0x16 | ||||||
|  | 	MAP_NORESERVE                     = 0x40 | ||||||
|  | 	MAP_RENAME                        = 0x20 | ||||||
|  | 	NET_RT_MAXID                      = 0x6 | ||||||
|  | 	RTF_PRCLONING                     = 0x10000 | ||||||
|  | 	RTM_OLDADD                        = 0x9 | ||||||
|  | 	RTM_OLDDEL                        = 0xa | ||||||
|  | 	SIOCADDRT                         = 0x8040720a | ||||||
|  | 	SIOCALIFADDR                      = 0x8118691b | ||||||
|  | 	SIOCDELRT                         = 0x8040720b | ||||||
|  | 	SIOCDLIFADDR                      = 0x8118691d | ||||||
|  | 	SIOCGLIFADDR                      = 0xc118691c | ||||||
|  | 	SIOCGLIFPHYADDR                   = 0xc118694b | ||||||
|  | 	SIOCSLIFPHYADDR                   = 0x8118694a | ||||||
|  | ) | ||||||
							
								
								
									
										226
									
								
								vendor/golang.org/x/sys/unix/errors_freebsd_arm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								vendor/golang.org/x/sys/unix/errors_freebsd_arm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | |||||||
|  | // Copyright 2017 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 unix | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	IFT_1822                          = 0x2 | ||||||
|  | 	IFT_A12MPPSWITCH                  = 0x82 | ||||||
|  | 	IFT_AAL2                          = 0xbb | ||||||
|  | 	IFT_AAL5                          = 0x31 | ||||||
|  | 	IFT_ADSL                          = 0x5e | ||||||
|  | 	IFT_AFLANE8023                    = 0x3b | ||||||
|  | 	IFT_AFLANE8025                    = 0x3c | ||||||
|  | 	IFT_ARAP                          = 0x58 | ||||||
|  | 	IFT_ARCNET                        = 0x23 | ||||||
|  | 	IFT_ARCNETPLUS                    = 0x24 | ||||||
|  | 	IFT_ASYNC                         = 0x54 | ||||||
|  | 	IFT_ATM                           = 0x25 | ||||||
|  | 	IFT_ATMDXI                        = 0x69 | ||||||
|  | 	IFT_ATMFUNI                       = 0x6a | ||||||
|  | 	IFT_ATMIMA                        = 0x6b | ||||||
|  | 	IFT_ATMLOGICAL                    = 0x50 | ||||||
|  | 	IFT_ATMRADIO                      = 0xbd | ||||||
|  | 	IFT_ATMSUBINTERFACE               = 0x86 | ||||||
|  | 	IFT_ATMVCIENDPT                   = 0xc2 | ||||||
|  | 	IFT_ATMVIRTUAL                    = 0x95 | ||||||
|  | 	IFT_BGPPOLICYACCOUNTING           = 0xa2 | ||||||
|  | 	IFT_BSC                           = 0x53 | ||||||
|  | 	IFT_CCTEMUL                       = 0x3d | ||||||
|  | 	IFT_CEPT                          = 0x13 | ||||||
|  | 	IFT_CES                           = 0x85 | ||||||
|  | 	IFT_CHANNEL                       = 0x46 | ||||||
|  | 	IFT_CNR                           = 0x55 | ||||||
|  | 	IFT_COFFEE                        = 0x84 | ||||||
|  | 	IFT_COMPOSITELINK                 = 0x9b | ||||||
|  | 	IFT_DCN                           = 0x8d | ||||||
|  | 	IFT_DIGITALPOWERLINE              = 0x8a | ||||||
|  | 	IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba | ||||||
|  | 	IFT_DLSW                          = 0x4a | ||||||
|  | 	IFT_DOCSCABLEDOWNSTREAM           = 0x80 | ||||||
|  | 	IFT_DOCSCABLEMACLAYER             = 0x7f | ||||||
|  | 	IFT_DOCSCABLEUPSTREAM             = 0x81 | ||||||
|  | 	IFT_DS0                           = 0x51 | ||||||
|  | 	IFT_DS0BUNDLE                     = 0x52 | ||||||
|  | 	IFT_DS1FDL                        = 0xaa | ||||||
|  | 	IFT_DS3                           = 0x1e | ||||||
|  | 	IFT_DTM                           = 0x8c | ||||||
|  | 	IFT_DVBASILN                      = 0xac | ||||||
|  | 	IFT_DVBASIOUT                     = 0xad | ||||||
|  | 	IFT_DVBRCCDOWNSTREAM              = 0x93 | ||||||
|  | 	IFT_DVBRCCMACLAYER                = 0x92 | ||||||
|  | 	IFT_DVBRCCUPSTREAM                = 0x94 | ||||||
|  | 	IFT_ENC                           = 0xf4 | ||||||
|  | 	IFT_EON                           = 0x19 | ||||||
|  | 	IFT_EPLRS                         = 0x57 | ||||||
|  | 	IFT_ESCON                         = 0x49 | ||||||
|  | 	IFT_ETHER                         = 0x6 | ||||||
|  | 	IFT_FAST                          = 0x7d | ||||||
|  | 	IFT_FASTETHER                     = 0x3e | ||||||
|  | 	IFT_FASTETHERFX                   = 0x45 | ||||||
|  | 	IFT_FDDI                          = 0xf | ||||||
|  | 	IFT_FIBRECHANNEL                  = 0x38 | ||||||
|  | 	IFT_FRAMERELAYINTERCONNECT        = 0x3a | ||||||
|  | 	IFT_FRAMERELAYMPI                 = 0x5c | ||||||
|  | 	IFT_FRDLCIENDPT                   = 0xc1 | ||||||
|  | 	IFT_FRELAY                        = 0x20 | ||||||
|  | 	IFT_FRELAYDCE                     = 0x2c | ||||||
|  | 	IFT_FRF16MFRBUNDLE                = 0xa3 | ||||||
|  | 	IFT_FRFORWARD                     = 0x9e | ||||||
|  | 	IFT_G703AT2MB                     = 0x43 | ||||||
|  | 	IFT_G703AT64K                     = 0x42 | ||||||
|  | 	IFT_GIF                           = 0xf0 | ||||||
|  | 	IFT_GIGABITETHERNET               = 0x75 | ||||||
|  | 	IFT_GR303IDT                      = 0xb2 | ||||||
|  | 	IFT_GR303RDT                      = 0xb1 | ||||||
|  | 	IFT_H323GATEKEEPER                = 0xa4 | ||||||
|  | 	IFT_H323PROXY                     = 0xa5 | ||||||
|  | 	IFT_HDH1822                       = 0x3 | ||||||
|  | 	IFT_HDLC                          = 0x76 | ||||||
|  | 	IFT_HDSL2                         = 0xa8 | ||||||
|  | 	IFT_HIPERLAN2                     = 0xb7 | ||||||
|  | 	IFT_HIPPI                         = 0x2f | ||||||
|  | 	IFT_HIPPIINTERFACE                = 0x39 | ||||||
|  | 	IFT_HOSTPAD                       = 0x5a | ||||||
|  | 	IFT_HSSI                          = 0x2e | ||||||
|  | 	IFT_HY                            = 0xe | ||||||
|  | 	IFT_IBM370PARCHAN                 = 0x48 | ||||||
|  | 	IFT_IDSL                          = 0x9a | ||||||
|  | 	IFT_IEEE80211                     = 0x47 | ||||||
|  | 	IFT_IEEE80212                     = 0x37 | ||||||
|  | 	IFT_IEEE8023ADLAG                 = 0xa1 | ||||||
|  | 	IFT_IFGSN                         = 0x91 | ||||||
|  | 	IFT_IMT                           = 0xbe | ||||||
|  | 	IFT_INTERLEAVE                    = 0x7c | ||||||
|  | 	IFT_IP                            = 0x7e | ||||||
|  | 	IFT_IPFORWARD                     = 0x8e | ||||||
|  | 	IFT_IPOVERATM                     = 0x72 | ||||||
|  | 	IFT_IPOVERCDLC                    = 0x6d | ||||||
|  | 	IFT_IPOVERCLAW                    = 0x6e | ||||||
|  | 	IFT_IPSWITCH                      = 0x4e | ||||||
|  | 	IFT_ISDN                          = 0x3f | ||||||
|  | 	IFT_ISDNBASIC                     = 0x14 | ||||||
|  | 	IFT_ISDNPRIMARY                   = 0x15 | ||||||
|  | 	IFT_ISDNS                         = 0x4b | ||||||
|  | 	IFT_ISDNU                         = 0x4c | ||||||
|  | 	IFT_ISO88022LLC                   = 0x29 | ||||||
|  | 	IFT_ISO88023                      = 0x7 | ||||||
|  | 	IFT_ISO88024                      = 0x8 | ||||||
|  | 	IFT_ISO88025                      = 0x9 | ||||||
|  | 	IFT_ISO88025CRFPINT               = 0x62 | ||||||
|  | 	IFT_ISO88025DTR                   = 0x56 | ||||||
|  | 	IFT_ISO88025FIBER                 = 0x73 | ||||||
|  | 	IFT_ISO88026                      = 0xa | ||||||
|  | 	IFT_ISUP                          = 0xb3 | ||||||
|  | 	IFT_L3IPXVLAN                     = 0x89 | ||||||
|  | 	IFT_LAPB                          = 0x10 | ||||||
|  | 	IFT_LAPD                          = 0x4d | ||||||
|  | 	IFT_LAPF                          = 0x77 | ||||||
|  | 	IFT_LOCALTALK                     = 0x2a | ||||||
|  | 	IFT_LOOP                          = 0x18 | ||||||
|  | 	IFT_MEDIAMAILOVERIP               = 0x8b | ||||||
|  | 	IFT_MFSIGLINK                     = 0xa7 | ||||||
|  | 	IFT_MIOX25                        = 0x26 | ||||||
|  | 	IFT_MODEM                         = 0x30 | ||||||
|  | 	IFT_MPC                           = 0x71 | ||||||
|  | 	IFT_MPLS                          = 0xa6 | ||||||
|  | 	IFT_MPLSTUNNEL                    = 0x96 | ||||||
|  | 	IFT_MSDSL                         = 0x8f | ||||||
|  | 	IFT_MVL                           = 0xbf | ||||||
|  | 	IFT_MYRINET                       = 0x63 | ||||||
|  | 	IFT_NFAS                          = 0xaf | ||||||
|  | 	IFT_NSIP                          = 0x1b | ||||||
|  | 	IFT_OPTICALCHANNEL                = 0xc3 | ||||||
|  | 	IFT_OPTICALTRANSPORT              = 0xc4 | ||||||
|  | 	IFT_OTHER                         = 0x1 | ||||||
|  | 	IFT_P10                           = 0xc | ||||||
|  | 	IFT_P80                           = 0xd | ||||||
|  | 	IFT_PARA                          = 0x22 | ||||||
|  | 	IFT_PFLOG                         = 0xf6 | ||||||
|  | 	IFT_PFSYNC                        = 0xf7 | ||||||
|  | 	IFT_PLC                           = 0xae | ||||||
|  | 	IFT_POS                           = 0xab | ||||||
|  | 	IFT_PPPMULTILINKBUNDLE            = 0x6c | ||||||
|  | 	IFT_PROPBWAP2MP                   = 0xb8 | ||||||
|  | 	IFT_PROPCNLS                      = 0x59 | ||||||
|  | 	IFT_PROPDOCSWIRELESSDOWNSTREAM    = 0xb5 | ||||||
|  | 	IFT_PROPDOCSWIRELESSMACLAYER      = 0xb4 | ||||||
|  | 	IFT_PROPDOCSWIRELESSUPSTREAM      = 0xb6 | ||||||
|  | 	IFT_PROPMUX                       = 0x36 | ||||||
|  | 	IFT_PROPWIRELESSP2P               = 0x9d | ||||||
|  | 	IFT_PTPSERIAL                     = 0x16 | ||||||
|  | 	IFT_PVC                           = 0xf1 | ||||||
|  | 	IFT_QLLC                          = 0x44 | ||||||
|  | 	IFT_RADIOMAC                      = 0xbc | ||||||
|  | 	IFT_RADSL                         = 0x5f | ||||||
|  | 	IFT_REACHDSL                      = 0xc0 | ||||||
|  | 	IFT_RFC1483                       = 0x9f | ||||||
|  | 	IFT_RS232                         = 0x21 | ||||||
|  | 	IFT_RSRB                          = 0x4f | ||||||
|  | 	IFT_SDLC                          = 0x11 | ||||||
|  | 	IFT_SDSL                          = 0x60 | ||||||
|  | 	IFT_SHDSL                         = 0xa9 | ||||||
|  | 	IFT_SIP                           = 0x1f | ||||||
|  | 	IFT_SLIP                          = 0x1c | ||||||
|  | 	IFT_SMDSDXI                       = 0x2b | ||||||
|  | 	IFT_SMDSICIP                      = 0x34 | ||||||
|  | 	IFT_SONET                         = 0x27 | ||||||
|  | 	IFT_SONETOVERHEADCHANNEL          = 0xb9 | ||||||
|  | 	IFT_SONETPATH                     = 0x32 | ||||||
|  | 	IFT_SONETVT                       = 0x33 | ||||||
|  | 	IFT_SRP                           = 0x97 | ||||||
|  | 	IFT_SS7SIGLINK                    = 0x9c | ||||||
|  | 	IFT_STACKTOSTACK                  = 0x6f | ||||||
|  | 	IFT_STARLAN                       = 0xb | ||||||
|  | 	IFT_STF                           = 0xd7 | ||||||
|  | 	IFT_T1                            = 0x12 | ||||||
|  | 	IFT_TDLC                          = 0x74 | ||||||
|  | 	IFT_TERMPAD                       = 0x5b | ||||||
|  | 	IFT_TR008                         = 0xb0 | ||||||
|  | 	IFT_TRANSPHDLC                    = 0x7b | ||||||
|  | 	IFT_TUNNEL                        = 0x83 | ||||||
|  | 	IFT_ULTRA                         = 0x1d | ||||||
|  | 	IFT_USB                           = 0xa0 | ||||||
|  | 	IFT_V11                           = 0x40 | ||||||
|  | 	IFT_V35                           = 0x2d | ||||||
|  | 	IFT_V36                           = 0x41 | ||||||
|  | 	IFT_V37                           = 0x78 | ||||||
|  | 	IFT_VDSL                          = 0x61 | ||||||
|  | 	IFT_VIRTUALIPADDRESS              = 0x70 | ||||||
|  | 	IFT_VOICEEM                       = 0x64 | ||||||
|  | 	IFT_VOICEENCAP                    = 0x67 | ||||||
|  | 	IFT_VOICEFXO                      = 0x65 | ||||||
|  | 	IFT_VOICEFXS                      = 0x66 | ||||||
|  | 	IFT_VOICEOVERATM                  = 0x98 | ||||||
|  | 	IFT_VOICEOVERFRAMERELAY           = 0x99 | ||||||
|  | 	IFT_VOICEOVERIP                   = 0x68 | ||||||
|  | 	IFT_X213                          = 0x5d | ||||||
|  | 	IFT_X25                           = 0x5 | ||||||
|  | 	IFT_X25DDN                        = 0x4 | ||||||
|  | 	IFT_X25HUNTGROUP                  = 0x7a | ||||||
|  | 	IFT_X25MLP                        = 0x79 | ||||||
|  | 	IFT_X25PLE                        = 0x28 | ||||||
|  | 	IFT_XETHER                        = 0x1a | ||||||
|  |  | ||||||
|  | 	// missing constants on FreeBSD-11.1-RELEASE, copied from old values in ztypes_freebsd_arm.go | ||||||
|  | 	IFF_SMART       = 0x20 | ||||||
|  | 	IFT_FAITH       = 0xf2 | ||||||
|  | 	IFT_IPXIP       = 0xf9 | ||||||
|  | 	IPPROTO_MAXID   = 0x34 | ||||||
|  | 	IPV6_FAITH      = 0x1d | ||||||
|  | 	IP_FAITH        = 0x16 | ||||||
|  | 	MAP_NORESERVE   = 0x40 | ||||||
|  | 	MAP_RENAME      = 0x20 | ||||||
|  | 	NET_RT_MAXID    = 0x6 | ||||||
|  | 	RTF_PRCLONING   = 0x10000 | ||||||
|  | 	RTM_OLDADD      = 0x9 | ||||||
|  | 	RTM_OLDDEL      = 0xa | ||||||
|  | 	SIOCADDRT       = 0x8030720a | ||||||
|  | 	SIOCALIFADDR    = 0x8118691b | ||||||
|  | 	SIOCDELRT       = 0x8030720b | ||||||
|  | 	SIOCDLIFADDR    = 0x8118691d | ||||||
|  | 	SIOCGLIFADDR    = 0xc118691c | ||||||
|  | 	SIOCGLIFPHYADDR = 0xc118694b | ||||||
|  | 	SIOCSLIFPHYADDR = 0x8118694a | ||||||
|  | ) | ||||||
							
								
								
									
										2
									
								
								vendor/golang.org/x/sys/unix/flock.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/golang.org/x/sys/unix/flock.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,5 +1,3 @@ | |||||||
| // +build linux darwin freebsd openbsd netbsd dragonfly |  | ||||||
|  |  | ||||||
| // Copyright 2014 The Go Authors. All rights reserved. | // Copyright 2014 The Go Authors. All rights reserved. | ||||||
| // Use of this source code is governed by a BSD-style | // Use of this source code is governed by a BSD-style | ||||||
| // license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								vendor/golang.org/x/sys/unix/gccgo_linux_sparc64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/golang.org/x/sys/unix/gccgo_linux_sparc64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,20 +0,0 @@ | |||||||
| // Copyright 2016 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. |  | ||||||
|  |  | ||||||
| // +build gccgo,linux,sparc64 |  | ||||||
|  |  | ||||||
| package unix |  | ||||||
|  |  | ||||||
| import "syscall" |  | ||||||
|  |  | ||||||
| //extern sysconf |  | ||||||
| func realSysconf(name int) int64 |  | ||||||
|  |  | ||||||
| func sysconf(name int) (n int64, err syscall.Errno) { |  | ||||||
| 	r := realSysconf(name) |  | ||||||
| 	if r < 0 { |  | ||||||
| 		return 0, syscall.GetErrno() |  | ||||||
| 	} |  | ||||||
| 	return r, 0 |  | ||||||
| } |  | ||||||
							
								
								
									
										482
									
								
								vendor/golang.org/x/sys/unix/linux/mkall.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										482
									
								
								vendor/golang.org/x/sys/unix/linux/mkall.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,482 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // linux/mkall.go - Generates all Linux zsysnum, zsyscall, zerror, and ztype | ||||||
|  | // files for all 11 linux architectures supported by the go compiler. See | ||||||
|  | // README.md for more information about the build system. | ||||||
|  |  | ||||||
|  | // To run it you must have a git checkout of the Linux kernel and glibc. Once | ||||||
|  | // the appropriate sources are ready, the program is run as: | ||||||
|  | //     go run linux/mkall.go <linux_dir> <glibc_dir> | ||||||
|  |  | ||||||
|  | // +build ignore | ||||||
|  |  | ||||||
|  | package main | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"os" | ||||||
|  | 	"os/exec" | ||||||
|  | 	"path/filepath" | ||||||
|  | 	"runtime" | ||||||
|  | 	"strings" | ||||||
|  | 	"unicode" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // These will be paths to the appropriate source directories. | ||||||
|  | var LinuxDir string | ||||||
|  | var GlibcDir string | ||||||
|  |  | ||||||
|  | const TempDir = "/tmp" | ||||||
|  | const IncludeDir = TempDir + "/include" // To hold our C headers | ||||||
|  | const BuildDir = TempDir + "/build"     // To hold intermediate build files | ||||||
|  |  | ||||||
|  | const GOOS = "linux"       // Only for Linux targets | ||||||
|  | const BuildArch = "amd64"  // Must be built on this architecture | ||||||
|  | const MinKernel = "2.6.23" // https://golang.org/doc/install#requirements | ||||||
|  |  | ||||||
|  | type target struct { | ||||||
|  | 	GoArch     string // Architecture name according to Go | ||||||
|  | 	LinuxArch  string // Architecture name according to the Linux Kernel | ||||||
|  | 	GNUArch    string // Architecture name according to GNU tools (https://wiki.debian.org/Multiarch/Tuples) | ||||||
|  | 	BigEndian  bool   // Default Little Endian | ||||||
|  | 	SignedChar bool   // Is -fsigned-char needed (default no) | ||||||
|  | 	Bits       int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // List of the 11 Linux targets supported by the go compiler. sparc64 is not | ||||||
|  | // currently supported, though a port is in progress. | ||||||
|  | var targets = []target{ | ||||||
|  | 	{ | ||||||
|  | 		GoArch:    "386", | ||||||
|  | 		LinuxArch: "x86", | ||||||
|  | 		GNUArch:   "i686-linux-gnu", // Note "i686" not "i386" | ||||||
|  | 		Bits:      32, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		GoArch:    "amd64", | ||||||
|  | 		LinuxArch: "x86", | ||||||
|  | 		GNUArch:   "x86_64-linux-gnu", | ||||||
|  | 		Bits:      64, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		GoArch:     "arm64", | ||||||
|  | 		LinuxArch:  "arm64", | ||||||
|  | 		GNUArch:    "aarch64-linux-gnu", | ||||||
|  | 		SignedChar: true, | ||||||
|  | 		Bits:       64, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		GoArch:    "arm", | ||||||
|  | 		LinuxArch: "arm", | ||||||
|  | 		GNUArch:   "arm-linux-gnueabi", | ||||||
|  | 		Bits:      32, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		GoArch:    "mips", | ||||||
|  | 		LinuxArch: "mips", | ||||||
|  | 		GNUArch:   "mips-linux-gnu", | ||||||
|  | 		BigEndian: true, | ||||||
|  | 		Bits:      32, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		GoArch:    "mipsle", | ||||||
|  | 		LinuxArch: "mips", | ||||||
|  | 		GNUArch:   "mipsel-linux-gnu", | ||||||
|  | 		Bits:      32, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		GoArch:    "mips64", | ||||||
|  | 		LinuxArch: "mips", | ||||||
|  | 		GNUArch:   "mips64-linux-gnuabi64", | ||||||
|  | 		BigEndian: true, | ||||||
|  | 		Bits:      64, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		GoArch:    "mips64le", | ||||||
|  | 		LinuxArch: "mips", | ||||||
|  | 		GNUArch:   "mips64el-linux-gnuabi64", | ||||||
|  | 		Bits:      64, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		GoArch:    "ppc64", | ||||||
|  | 		LinuxArch: "powerpc", | ||||||
|  | 		GNUArch:   "powerpc64-linux-gnu", | ||||||
|  | 		BigEndian: true, | ||||||
|  | 		Bits:      64, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		GoArch:    "ppc64le", | ||||||
|  | 		LinuxArch: "powerpc", | ||||||
|  | 		GNUArch:   "powerpc64le-linux-gnu", | ||||||
|  | 		Bits:      64, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		GoArch:     "s390x", | ||||||
|  | 		LinuxArch:  "s390", | ||||||
|  | 		GNUArch:    "s390x-linux-gnu", | ||||||
|  | 		BigEndian:  true, | ||||||
|  | 		SignedChar: true, | ||||||
|  | 		Bits:       64, | ||||||
|  | 	}, | ||||||
|  | 	// { | ||||||
|  | 	// 	GoArch:    "sparc64", | ||||||
|  | 	// 	LinuxArch: "sparc", | ||||||
|  | 	// 	GNUArch:   "sparc64-linux-gnu", | ||||||
|  | 	// 	BigEndian: true, | ||||||
|  | 	// 	Bits:      64, | ||||||
|  | 	// }, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ptracePairs is a list of pairs of targets that can, in some cases, | ||||||
|  | // run each other's binaries. | ||||||
|  | var ptracePairs = []struct{ a1, a2 string }{ | ||||||
|  | 	{"386", "amd64"}, | ||||||
|  | 	{"arm", "arm64"}, | ||||||
|  | 	{"mips", "mips64"}, | ||||||
|  | 	{"mipsle", "mips64le"}, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func main() { | ||||||
|  | 	if runtime.GOOS != GOOS || runtime.GOARCH != BuildArch { | ||||||
|  | 		fmt.Printf("Build system has GOOS_GOARCH = %s_%s, need %s_%s\n", | ||||||
|  | 			runtime.GOOS, runtime.GOARCH, GOOS, BuildArch) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Check that we are using the new build system if we should | ||||||
|  | 	if os.Getenv("GOLANG_SYS_BUILD") != "docker" { | ||||||
|  | 		fmt.Println("In the new build system, mkall.go should not be called directly.") | ||||||
|  | 		fmt.Println("See README.md") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Parse the command line options | ||||||
|  | 	if len(os.Args) != 3 { | ||||||
|  | 		fmt.Println("USAGE: go run linux/mkall.go <linux_dir> <glibc_dir>") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	LinuxDir = os.Args[1] | ||||||
|  | 	GlibcDir = os.Args[2] | ||||||
|  |  | ||||||
|  | 	for _, t := range targets { | ||||||
|  | 		fmt.Printf("----- GENERATING: %s -----\n", t.GoArch) | ||||||
|  | 		if err := t.generateFiles(); err != nil { | ||||||
|  | 			fmt.Printf("%v\n***** FAILURE:    %s *****\n\n", err, t.GoArch) | ||||||
|  | 		} else { | ||||||
|  | 			fmt.Printf("----- SUCCESS:    %s -----\n\n", t.GoArch) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	fmt.Printf("----- GENERATING ptrace pairs -----\n") | ||||||
|  | 	ok := true | ||||||
|  | 	for _, p := range ptracePairs { | ||||||
|  | 		if err := generatePtracePair(p.a1, p.a2); err != nil { | ||||||
|  | 			fmt.Printf("%v\n***** FAILURE: %s/%s *****\n\n", err, p.a1, p.a2) | ||||||
|  | 			ok = false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if ok { | ||||||
|  | 		fmt.Printf("----- SUCCESS ptrace pairs    -----\n\n") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Makes an exec.Cmd with Stderr attached to os.Stderr | ||||||
|  | func makeCommand(name string, args ...string) *exec.Cmd { | ||||||
|  | 	cmd := exec.Command(name, args...) | ||||||
|  | 	cmd.Stderr = os.Stderr | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Runs the command, pipes output to a formatter, pipes that to an output file. | ||||||
|  | func (t *target) commandFormatOutput(formatter string, outputFile string, | ||||||
|  | 	name string, args ...string) (err error) { | ||||||
|  | 	mainCmd := makeCommand(name, args...) | ||||||
|  |  | ||||||
|  | 	fmtCmd := makeCommand(formatter) | ||||||
|  | 	if formatter == "mkpost" { | ||||||
|  | 		fmtCmd = makeCommand("go", "run", "mkpost.go") | ||||||
|  | 		// Set GOARCH_TARGET so mkpost knows what GOARCH is.. | ||||||
|  | 		fmtCmd.Env = append(os.Environ(), "GOARCH_TARGET="+t.GoArch) | ||||||
|  | 		// Set GOARCH to host arch for mkpost, so it can run natively. | ||||||
|  | 		for i, s := range fmtCmd.Env { | ||||||
|  | 			if strings.HasPrefix(s, "GOARCH=") { | ||||||
|  | 				fmtCmd.Env[i] = "GOARCH=" + BuildArch | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// mainCmd | fmtCmd > outputFile | ||||||
|  | 	if fmtCmd.Stdin, err = mainCmd.StdoutPipe(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if fmtCmd.Stdout, err = os.Create(outputFile); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Make sure the formatter eventually closes | ||||||
|  | 	if err = fmtCmd.Start(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	defer func() { | ||||||
|  | 		fmtErr := fmtCmd.Wait() | ||||||
|  | 		if err == nil { | ||||||
|  | 			err = fmtErr | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	return mainCmd.Run() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Generates all the files for a Linux target | ||||||
|  | func (t *target) generateFiles() error { | ||||||
|  | 	// Setup environment variables | ||||||
|  | 	os.Setenv("GOOS", GOOS) | ||||||
|  | 	os.Setenv("GOARCH", t.GoArch) | ||||||
|  |  | ||||||
|  | 	// Get appropriate compiler and emulator (unless on x86) | ||||||
|  | 	if t.LinuxArch != "x86" { | ||||||
|  | 		// Check/Setup cross compiler | ||||||
|  | 		compiler := t.GNUArch + "-gcc" | ||||||
|  | 		if _, err := exec.LookPath(compiler); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		os.Setenv("CC", compiler) | ||||||
|  |  | ||||||
|  | 		// Check/Setup emulator (usually first component of GNUArch) | ||||||
|  | 		qemuArchName := t.GNUArch[:strings.Index(t.GNUArch, "-")] | ||||||
|  | 		if t.LinuxArch == "powerpc" { | ||||||
|  | 			qemuArchName = t.GoArch | ||||||
|  | 		} | ||||||
|  | 		os.Setenv("GORUN", "qemu-"+qemuArchName) | ||||||
|  | 	} else { | ||||||
|  | 		os.Setenv("CC", "gcc") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Make the include directory and fill it with headers | ||||||
|  | 	if err := os.MkdirAll(IncludeDir, os.ModePerm); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer os.RemoveAll(IncludeDir) | ||||||
|  | 	if err := t.makeHeaders(); err != nil { | ||||||
|  | 		return fmt.Errorf("could not make header files: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Println("header files generated") | ||||||
|  |  | ||||||
|  | 	// Make each of the four files | ||||||
|  | 	if err := t.makeZSysnumFile(); err != nil { | ||||||
|  | 		return fmt.Errorf("could not make zsysnum file: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Println("zsysnum file generated") | ||||||
|  |  | ||||||
|  | 	if err := t.makeZSyscallFile(); err != nil { | ||||||
|  | 		return fmt.Errorf("could not make zsyscall file: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Println("zsyscall file generated") | ||||||
|  |  | ||||||
|  | 	if err := t.makeZTypesFile(); err != nil { | ||||||
|  | 		return fmt.Errorf("could not make ztypes file: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Println("ztypes file generated") | ||||||
|  |  | ||||||
|  | 	if err := t.makeZErrorsFile(); err != nil { | ||||||
|  | 		return fmt.Errorf("could not make zerrors file: %v", err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Println("zerrors file generated") | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Create the Linux and glibc headers in the include directory. | ||||||
|  | func (t *target) makeHeaders() error { | ||||||
|  | 	// Make the Linux headers we need for this architecture | ||||||
|  | 	linuxMake := makeCommand("make", "headers_install", "ARCH="+t.LinuxArch, "INSTALL_HDR_PATH="+TempDir) | ||||||
|  | 	linuxMake.Dir = LinuxDir | ||||||
|  | 	if err := linuxMake.Run(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// A Temporary build directory for glibc | ||||||
|  | 	if err := os.MkdirAll(BuildDir, os.ModePerm); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	defer os.RemoveAll(BuildDir) | ||||||
|  |  | ||||||
|  | 	// Make the glibc headers we need for this architecture | ||||||
|  | 	confScript := filepath.Join(GlibcDir, "configure") | ||||||
|  | 	glibcConf := makeCommand(confScript, "--prefix="+TempDir, "--host="+t.GNUArch, "--enable-kernel="+MinKernel) | ||||||
|  | 	glibcConf.Dir = BuildDir | ||||||
|  | 	if err := glibcConf.Run(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	glibcMake := makeCommand("make", "install-headers") | ||||||
|  | 	glibcMake.Dir = BuildDir | ||||||
|  | 	if err := glibcMake.Run(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	// We only need an empty stubs file | ||||||
|  | 	stubsFile := filepath.Join(IncludeDir, "gnu/stubs.h") | ||||||
|  | 	if file, err := os.Create(stubsFile); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} else { | ||||||
|  | 		file.Close() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // makes the zsysnum_linux_$GOARCH.go file | ||||||
|  | func (t *target) makeZSysnumFile() error { | ||||||
|  | 	zsysnumFile := fmt.Sprintf("zsysnum_linux_%s.go", t.GoArch) | ||||||
|  | 	unistdFile := filepath.Join(IncludeDir, "asm/unistd.h") | ||||||
|  |  | ||||||
|  | 	args := append(t.cFlags(), unistdFile) | ||||||
|  | 	return t.commandFormatOutput("gofmt", zsysnumFile, "linux/mksysnum.pl", args...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // makes the zsyscall_linux_$GOARCH.go file | ||||||
|  | func (t *target) makeZSyscallFile() error { | ||||||
|  | 	zsyscallFile := fmt.Sprintf("zsyscall_linux_%s.go", t.GoArch) | ||||||
|  | 	// Find the correct architecture syscall file (might end with x.go) | ||||||
|  | 	archSyscallFile := fmt.Sprintf("syscall_linux_%s.go", t.GoArch) | ||||||
|  | 	if _, err := os.Stat(archSyscallFile); os.IsNotExist(err) { | ||||||
|  | 		shortArch := strings.TrimSuffix(t.GoArch, "le") | ||||||
|  | 		archSyscallFile = fmt.Sprintf("syscall_linux_%sx.go", shortArch) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	args := append(t.mksyscallFlags(), "-tags", "linux,"+t.GoArch, | ||||||
|  | 		"syscall_linux.go", archSyscallFile) | ||||||
|  | 	return t.commandFormatOutput("gofmt", zsyscallFile, "./mksyscall.pl", args...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // makes the zerrors_linux_$GOARCH.go file | ||||||
|  | func (t *target) makeZErrorsFile() error { | ||||||
|  | 	zerrorsFile := fmt.Sprintf("zerrors_linux_%s.go", t.GoArch) | ||||||
|  |  | ||||||
|  | 	return t.commandFormatOutput("gofmt", zerrorsFile, "./mkerrors.sh", t.cFlags()...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // makes the ztypes_linux_$GOARCH.go file | ||||||
|  | func (t *target) makeZTypesFile() error { | ||||||
|  | 	ztypesFile := fmt.Sprintf("ztypes_linux_%s.go", t.GoArch) | ||||||
|  |  | ||||||
|  | 	args := []string{"tool", "cgo", "-godefs", "--"} | ||||||
|  | 	args = append(args, t.cFlags()...) | ||||||
|  | 	args = append(args, "linux/types.go") | ||||||
|  | 	return t.commandFormatOutput("mkpost", ztypesFile, "go", args...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Flags that should be given to gcc and cgo for this target | ||||||
|  | func (t *target) cFlags() []string { | ||||||
|  | 	// Compile statically to avoid cross-architecture dynamic linking. | ||||||
|  | 	flags := []string{"-Wall", "-Werror", "-static", "-I" + IncludeDir} | ||||||
|  |  | ||||||
|  | 	// Architecture-specific flags | ||||||
|  | 	if t.SignedChar { | ||||||
|  | 		flags = append(flags, "-fsigned-char") | ||||||
|  | 	} | ||||||
|  | 	if t.LinuxArch == "x86" { | ||||||
|  | 		flags = append(flags, fmt.Sprintf("-m%d", t.Bits)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return flags | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Flags that should be given to mksyscall for this target | ||||||
|  | func (t *target) mksyscallFlags() (flags []string) { | ||||||
|  | 	if t.Bits == 32 { | ||||||
|  | 		if t.BigEndian { | ||||||
|  | 			flags = append(flags, "-b32") | ||||||
|  | 		} else { | ||||||
|  | 			flags = append(flags, "-l32") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// This flag menas a 64-bit value should use (even, odd)-pair. | ||||||
|  | 	if t.GoArch == "arm" || (t.LinuxArch == "mips" && t.Bits == 32) { | ||||||
|  | 		flags = append(flags, "-arm") | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // generatePtracePair takes a pair of GOARCH values that can run each | ||||||
|  | // other's binaries, such as 386 and amd64. It extracts the PtraceRegs | ||||||
|  | // type for each one. It writes a new file defining the types | ||||||
|  | // PtraceRegsArch1 and PtraceRegsArch2 and the corresponding functions | ||||||
|  | // Ptrace{Get,Set}Regs{arch1,arch2}. This permits debugging the other | ||||||
|  | // binary on a native system. | ||||||
|  | func generatePtracePair(arch1, arch2 string) error { | ||||||
|  | 	def1, err := ptraceDef(arch1) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	def2, err := ptraceDef(arch2) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	f, err := os.Create(fmt.Sprintf("zptrace%s_linux.go", arch1)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	buf := bufio.NewWriter(f) | ||||||
|  | 	fmt.Fprintf(buf, "// Code generated by linux/mkall.go generatePtracePair(%s, %s). DO NOT EDIT.\n", arch1, arch2) | ||||||
|  | 	fmt.Fprintf(buf, "\n") | ||||||
|  | 	fmt.Fprintf(buf, "// +build linux\n") | ||||||
|  | 	fmt.Fprintf(buf, "// +build %s %s\n", arch1, arch2) | ||||||
|  | 	fmt.Fprintf(buf, "\n") | ||||||
|  | 	fmt.Fprintf(buf, "package unix\n") | ||||||
|  | 	fmt.Fprintf(buf, "\n") | ||||||
|  | 	fmt.Fprintf(buf, "%s\n", `import "unsafe"`) | ||||||
|  | 	fmt.Fprintf(buf, "\n") | ||||||
|  | 	writeOnePtrace(buf, arch1, def1) | ||||||
|  | 	fmt.Fprintf(buf, "\n") | ||||||
|  | 	writeOnePtrace(buf, arch2, def2) | ||||||
|  | 	if err := buf.Flush(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if err := f.Close(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ptraceDef returns the definition of PtraceRegs for arch. | ||||||
|  | func ptraceDef(arch string) (string, error) { | ||||||
|  | 	filename := fmt.Sprintf("ztypes_linux_%s.go", arch) | ||||||
|  | 	data, err := ioutil.ReadFile(filename) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", fmt.Errorf("reading %s: %v", filename, err) | ||||||
|  | 	} | ||||||
|  | 	start := bytes.Index(data, []byte("type PtraceRegs struct")) | ||||||
|  | 	if start < 0 { | ||||||
|  | 		return "", fmt.Errorf("%s: no definition of PtraceRegs", filename) | ||||||
|  | 	} | ||||||
|  | 	data = data[start:] | ||||||
|  | 	end := bytes.Index(data, []byte("\n}\n")) | ||||||
|  | 	if end < 0 { | ||||||
|  | 		return "", fmt.Errorf("%s: can't find end of PtraceRegs definition", filename) | ||||||
|  | 	} | ||||||
|  | 	return string(data[:end+2]), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // writeOnePtrace writes out the ptrace definitions for arch. | ||||||
|  | func writeOnePtrace(w io.Writer, arch, def string) { | ||||||
|  | 	uarch := string(unicode.ToUpper(rune(arch[0]))) + arch[1:] | ||||||
|  | 	fmt.Fprintf(w, "// PtraceRegs%s is the registers used by %s binaries.\n", uarch, arch) | ||||||
|  | 	fmt.Fprintf(w, "%s\n", strings.Replace(def, "PtraceRegs", "PtraceRegs"+uarch, 1)) | ||||||
|  | 	fmt.Fprintf(w, "\n") | ||||||
|  | 	fmt.Fprintf(w, "// PtraceGetRegs%s fetches the registers used by %s binaries.\n", uarch, arch) | ||||||
|  | 	fmt.Fprintf(w, "func PtraceGetRegs%s(pid int, regsout *PtraceRegs%s) error {\n", uarch, uarch) | ||||||
|  | 	fmt.Fprintf(w, "\treturn ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))\n") | ||||||
|  | 	fmt.Fprintf(w, "}\n") | ||||||
|  | 	fmt.Fprintf(w, "\n") | ||||||
|  | 	fmt.Fprintf(w, "// PtraceSetRegs%s sets the registers used by %s binaries.\n", uarch, arch) | ||||||
|  | 	fmt.Fprintf(w, "func PtraceSetRegs%s(pid int, regs *PtraceRegs%s) error {\n", uarch, uarch) | ||||||
|  | 	fmt.Fprintf(w, "\treturn ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))\n") | ||||||
|  | 	fmt.Fprintf(w, "}\n") | ||||||
|  | } | ||||||
							
								
								
									
										155
									
								
								vendor/golang.org/x/sys/unix/types_linux.go → vendor/golang.org/x/sys/unix/linux/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										155
									
								
								vendor/golang.org/x/sys/unix/types_linux.go → vendor/golang.org/x/sys/unix/linux/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -5,7 +5,7 @@ | |||||||
| // +build ignore | // +build ignore | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
| Input to cgo -godefs.  See also mkerrors.sh and mkall.sh | Input to cgo -godefs.  See README.md | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| // +godefs map struct_in_addr [4]byte /* in_addr */ | // +godefs map struct_in_addr [4]byte /* in_addr */ | ||||||
| @@ -20,7 +20,6 @@ package unix | |||||||
| #define _GNU_SOURCE | #define _GNU_SOURCE | ||||||
| 
 | 
 | ||||||
| #include <dirent.h> | #include <dirent.h> | ||||||
| #include <fcntl.h> |  | ||||||
| #include <netinet/in.h> | #include <netinet/in.h> | ||||||
| #include <netinet/tcp.h> | #include <netinet/tcp.h> | ||||||
| #include <netpacket/packet.h> | #include <netpacket/packet.h> | ||||||
| @@ -29,6 +28,7 @@ package unix | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <sys/epoll.h> | #include <sys/epoll.h> | ||||||
| #include <sys/inotify.h> | #include <sys/inotify.h> | ||||||
|  | #include <sys/ioctl.h> | ||||||
| #include <sys/mman.h> | #include <sys/mman.h> | ||||||
| #include <sys/mount.h> | #include <sys/mount.h> | ||||||
| #include <sys/param.h> | #include <sys/param.h> | ||||||
| @@ -36,31 +36,83 @@ package unix | |||||||
| #include <sys/resource.h> | #include <sys/resource.h> | ||||||
| #include <sys/select.h> | #include <sys/select.h> | ||||||
| #include <sys/signal.h> | #include <sys/signal.h> | ||||||
| #include <sys/stat.h> |  | ||||||
| #include <sys/statfs.h> | #include <sys/statfs.h> | ||||||
| #include <sys/sysinfo.h> | #include <sys/sysinfo.h> | ||||||
| #include <sys/time.h> | #include <sys/time.h> | ||||||
| #include <sys/times.h> | #include <sys/times.h> | ||||||
| #include <sys/timex.h> | #include <sys/timex.h> | ||||||
| #include <sys/types.h> |  | ||||||
| #include <sys/un.h> | #include <sys/un.h> | ||||||
| #include <sys/user.h> | #include <sys/user.h> | ||||||
| #include <sys/utsname.h> | #include <sys/utsname.h> | ||||||
| #include <sys/wait.h> | #include <sys/wait.h> | ||||||
| #include <linux/filter.h> | #include <linux/filter.h> | ||||||
|  | #include <linux/keyctl.h> | ||||||
| #include <linux/netlink.h> | #include <linux/netlink.h> | ||||||
|  | #include <linux/perf_event.h> | ||||||
| #include <linux/rtnetlink.h> | #include <linux/rtnetlink.h> | ||||||
| #include <linux/icmpv6.h> | #include <linux/icmpv6.h> | ||||||
| #include <asm/termbits.h> | #include <asm/termbits.h> | ||||||
|  | #include <asm/ptrace.h> | ||||||
| #include <time.h> | #include <time.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <ustat.h> | #include <ustat.h> | ||||||
| #include <utime.h> | #include <utime.h> | ||||||
| #include <bluetooth/bluetooth.h> |  | ||||||
| #include <bluetooth/hci.h> |  | ||||||
| #include <linux/can.h> | #include <linux/can.h> | ||||||
| #include <linux/if_alg.h> | #include <linux/if_alg.h> | ||||||
|  | #include <linux/fs.h> | ||||||
| #include <linux/vm_sockets.h> | #include <linux/vm_sockets.h> | ||||||
|  | #include <linux/random.h> | ||||||
|  | #include <linux/taskstats.h> | ||||||
|  | #include <linux/genetlink.h> | ||||||
|  | 
 | ||||||
|  | // On mips64, the glibc stat and kernel stat do not agree | ||||||
|  | #if (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI64) | ||||||
|  | 
 | ||||||
|  | // Use the stat defined by the kernel with a few modifications. These are: | ||||||
|  | //	* The time fields (like st_atime and st_atimensec) use the timespec | ||||||
|  | //	  struct (like st_atim) for consitancy with the glibc fields. | ||||||
|  | //	* The padding fields get different names to not break compatibility. | ||||||
|  | //	* st_blocks is signed, again for compatibility. | ||||||
|  | struct stat { | ||||||
|  | 	unsigned int		st_dev; | ||||||
|  | 	unsigned int		st_pad1[3]; // Reserved for st_dev expansion | ||||||
|  | 
 | ||||||
|  | 	unsigned long		st_ino; | ||||||
|  | 
 | ||||||
|  | 	mode_t			st_mode; | ||||||
|  | 	__u32			st_nlink; | ||||||
|  | 
 | ||||||
|  | 	uid_t			st_uid; | ||||||
|  | 	gid_t			st_gid; | ||||||
|  | 
 | ||||||
|  | 	unsigned int		st_rdev; | ||||||
|  | 	unsigned int		st_pad2[3]; // Reserved for st_rdev expansion | ||||||
|  | 
 | ||||||
|  | 	off_t			st_size; | ||||||
|  | 
 | ||||||
|  | 	// These are declared as speperate fields in the kernel. Here we use | ||||||
|  | 	// the timespec struct for consistancy with the other stat structs. | ||||||
|  | 	struct timespec		st_atim; | ||||||
|  | 	struct timespec		st_mtim; | ||||||
|  | 	struct timespec		st_ctim; | ||||||
|  | 
 | ||||||
|  | 	unsigned int		st_blksize; | ||||||
|  | 	unsigned int		st_pad4; | ||||||
|  | 
 | ||||||
|  | 	long			st_blocks; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // These are needed because we do not include fcntl.h or sys/types.h | ||||||
|  | #include <linux/fcntl.h> | ||||||
|  | #include <linux/fadvise.h> | ||||||
|  | 
 | ||||||
|  | #else | ||||||
|  | 
 | ||||||
|  | // Use the stat defined by glibc | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef TCSETS2 | #ifdef TCSETS2 | ||||||
| // On systems that have "struct termios2" use this as type Termios. | // On systems that have "struct termios2" use this as type Termios. | ||||||
| @@ -87,6 +139,13 @@ struct sockaddr_any { | |||||||
| 	char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; | 	char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | // copied from /usr/include/bluetooth/hci.h | ||||||
|  | struct sockaddr_hci { | ||||||
|  |         sa_family_t     hci_family; | ||||||
|  |         unsigned short  hci_dev; | ||||||
|  |         unsigned short  hci_channel; | ||||||
|  | };; | ||||||
|  | 
 | ||||||
| // copied from /usr/include/linux/un.h | // copied from /usr/include/linux/un.h | ||||||
| struct my_sockaddr_un { | struct my_sockaddr_un { | ||||||
| 	sa_family_t sun_family; | 	sa_family_t sun_family; | ||||||
| @@ -102,10 +161,8 @@ struct my_sockaddr_un { | |||||||
| typedef struct user_regs PtraceRegs; | typedef struct user_regs PtraceRegs; | ||||||
| #elif defined(__aarch64__) | #elif defined(__aarch64__) | ||||||
| typedef struct user_pt_regs PtraceRegs; | typedef struct user_pt_regs PtraceRegs; | ||||||
| #elif defined(__powerpc64__) | #elif defined(__mips__) || defined(__powerpc64__) | ||||||
| typedef struct pt_regs PtraceRegs; | typedef struct pt_regs PtraceRegs; | ||||||
| #elif defined(__mips__) |  | ||||||
| typedef struct user PtraceRegs; |  | ||||||
| #elif defined(__s390x__) | #elif defined(__s390x__) | ||||||
| typedef struct _user_regs_struct PtraceRegs; | typedef struct _user_regs_struct PtraceRegs; | ||||||
| #elif defined(__sparc__) | #elif defined(__sparc__) | ||||||
| @@ -196,6 +253,16 @@ type Fsid C.fsid_t | |||||||
| 
 | 
 | ||||||
| type Flock_t C.struct_flock | type Flock_t C.struct_flock | ||||||
| 
 | 
 | ||||||
|  | // Filesystem Encryption | ||||||
|  | 
 | ||||||
|  | type FscryptPolicy C.struct_fscrypt_policy | ||||||
|  | 
 | ||||||
|  | type FscryptKey C.struct_fscrypt_key | ||||||
|  | 
 | ||||||
|  | // Structure for Keyctl | ||||||
|  | 
 | ||||||
|  | type KeyctlDHParams C.struct_keyctl_dh_params | ||||||
|  | 
 | ||||||
| // Advice to Fadvise | // Advice to Fadvise | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| @@ -243,6 +310,8 @@ type IPMreqn C.struct_ip_mreqn | |||||||
| 
 | 
 | ||||||
| type IPv6Mreq C.struct_ipv6_mreq | type IPv6Mreq C.struct_ipv6_mreq | ||||||
| 
 | 
 | ||||||
|  | type PacketMreq C.struct_packet_mreq | ||||||
|  | 
 | ||||||
| type Msghdr C.struct_msghdr | type Msghdr C.struct_msghdr | ||||||
| 
 | 
 | ||||||
| type Cmsghdr C.struct_cmsghdr | type Cmsghdr C.struct_cmsghdr | ||||||
| @@ -271,9 +340,11 @@ const ( | |||||||
| 	SizeofSockaddrALG       = C.sizeof_struct_sockaddr_alg | 	SizeofSockaddrALG       = C.sizeof_struct_sockaddr_alg | ||||||
| 	SizeofSockaddrVM        = C.sizeof_struct_sockaddr_vm | 	SizeofSockaddrVM        = C.sizeof_struct_sockaddr_vm | ||||||
| 	SizeofLinger            = C.sizeof_struct_linger | 	SizeofLinger            = C.sizeof_struct_linger | ||||||
|  | 	SizeofIovec             = C.sizeof_struct_iovec | ||||||
| 	SizeofIPMreq            = C.sizeof_struct_ip_mreq | 	SizeofIPMreq            = C.sizeof_struct_ip_mreq | ||||||
| 	SizeofIPMreqn           = C.sizeof_struct_ip_mreqn | 	SizeofIPMreqn           = C.sizeof_struct_ip_mreqn | ||||||
| 	SizeofIPv6Mreq          = C.sizeof_struct_ipv6_mreq | 	SizeofIPv6Mreq          = C.sizeof_struct_ipv6_mreq | ||||||
|  | 	SizeofPacketMreq        = C.sizeof_struct_packet_mreq | ||||||
| 	SizeofMsghdr            = C.sizeof_struct_msghdr | 	SizeofMsghdr            = C.sizeof_struct_msghdr | ||||||
| 	SizeofCmsghdr           = C.sizeof_struct_cmsghdr | 	SizeofCmsghdr           = C.sizeof_struct_cmsghdr | ||||||
| 	SizeofInet4Pktinfo      = C.sizeof_struct_in_pktinfo | 	SizeofInet4Pktinfo      = C.sizeof_struct_in_pktinfo | ||||||
| @@ -421,11 +492,11 @@ const SizeofInotifyEvent = C.sizeof_struct_inotify_event | |||||||
| type PtraceRegs C.PtraceRegs | type PtraceRegs C.PtraceRegs | ||||||
| 
 | 
 | ||||||
| // Structures contained in PtraceRegs on s390x (exported by mkpost.go) | // Structures contained in PtraceRegs on s390x (exported by mkpost.go) | ||||||
| type ptracePsw C.ptracePsw | type PtracePsw C.ptracePsw | ||||||
| 
 | 
 | ||||||
| type ptraceFpregs C.ptraceFpregs | type PtraceFpregs C.ptraceFpregs | ||||||
| 
 | 
 | ||||||
| type ptracePer C.ptracePer | type PtracePer C.ptracePer | ||||||
| 
 | 
 | ||||||
| // Misc | // Misc | ||||||
| 
 | 
 | ||||||
| @@ -441,6 +512,7 @@ type EpollEvent C.struct_my_epoll_event | |||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	AT_FDCWD            = C.AT_FDCWD | 	AT_FDCWD            = C.AT_FDCWD | ||||||
|  | 	AT_NO_AUTOMOUNT     = C.AT_NO_AUTOMOUNT | ||||||
| 	AT_REMOVEDIR        = C.AT_REMOVEDIR | 	AT_REMOVEDIR        = C.AT_REMOVEDIR | ||||||
| 	AT_SYMLINK_FOLLOW   = C.AT_SYMLINK_FOLLOW | 	AT_SYMLINK_FOLLOW   = C.AT_SYMLINK_FOLLOW | ||||||
| 	AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW | 	AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW | ||||||
| @@ -460,10 +532,65 @@ const ( | |||||||
| 
 | 
 | ||||||
| type Sigset_t C.sigset_t | type Sigset_t C.sigset_t | ||||||
| 
 | 
 | ||||||
| // sysconf information | const RNDGETENTCNT = C.RNDGETENTCNT | ||||||
| 
 | 
 | ||||||
| const _SC_PAGESIZE = C._SC_PAGESIZE | const PERF_IOC_FLAG_GROUP = C.PERF_IOC_FLAG_GROUP | ||||||
| 
 | 
 | ||||||
| // Terminal handling | // Terminal handling | ||||||
| 
 | 
 | ||||||
| type Termios C.termios_t | type Termios C.termios_t | ||||||
|  | 
 | ||||||
|  | type Winsize C.struct_winsize | ||||||
|  | 
 | ||||||
|  | // Taskstats | ||||||
|  | 
 | ||||||
|  | type Taskstats C.struct_taskstats | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	TASKSTATS_CMD_UNSPEC                  = C.TASKSTATS_CMD_UNSPEC | ||||||
|  | 	TASKSTATS_CMD_GET                     = C.TASKSTATS_CMD_GET | ||||||
|  | 	TASKSTATS_CMD_NEW                     = C.TASKSTATS_CMD_NEW | ||||||
|  | 	TASKSTATS_TYPE_UNSPEC                 = C.TASKSTATS_TYPE_UNSPEC | ||||||
|  | 	TASKSTATS_TYPE_PID                    = C.TASKSTATS_TYPE_PID | ||||||
|  | 	TASKSTATS_TYPE_TGID                   = C.TASKSTATS_TYPE_TGID | ||||||
|  | 	TASKSTATS_TYPE_STATS                  = C.TASKSTATS_TYPE_STATS | ||||||
|  | 	TASKSTATS_TYPE_AGGR_PID               = C.TASKSTATS_TYPE_AGGR_PID | ||||||
|  | 	TASKSTATS_TYPE_AGGR_TGID              = C.TASKSTATS_TYPE_AGGR_TGID | ||||||
|  | 	TASKSTATS_TYPE_NULL                   = C.TASKSTATS_TYPE_NULL | ||||||
|  | 	TASKSTATS_CMD_ATTR_UNSPEC             = C.TASKSTATS_CMD_ATTR_UNSPEC | ||||||
|  | 	TASKSTATS_CMD_ATTR_PID                = C.TASKSTATS_CMD_ATTR_PID | ||||||
|  | 	TASKSTATS_CMD_ATTR_TGID               = C.TASKSTATS_CMD_ATTR_TGID | ||||||
|  | 	TASKSTATS_CMD_ATTR_REGISTER_CPUMASK   = C.TASKSTATS_CMD_ATTR_REGISTER_CPUMASK | ||||||
|  | 	TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK = C.TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Generic netlink | ||||||
|  | 
 | ||||||
|  | type Genlmsghdr C.struct_genlmsghdr | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	CTRL_CMD_UNSPEC            = C.CTRL_CMD_UNSPEC | ||||||
|  | 	CTRL_CMD_NEWFAMILY         = C.CTRL_CMD_NEWFAMILY | ||||||
|  | 	CTRL_CMD_DELFAMILY         = C.CTRL_CMD_DELFAMILY | ||||||
|  | 	CTRL_CMD_GETFAMILY         = C.CTRL_CMD_GETFAMILY | ||||||
|  | 	CTRL_CMD_NEWOPS            = C.CTRL_CMD_NEWOPS | ||||||
|  | 	CTRL_CMD_DELOPS            = C.CTRL_CMD_DELOPS | ||||||
|  | 	CTRL_CMD_GETOPS            = C.CTRL_CMD_GETOPS | ||||||
|  | 	CTRL_CMD_NEWMCAST_GRP      = C.CTRL_CMD_NEWMCAST_GRP | ||||||
|  | 	CTRL_CMD_DELMCAST_GRP      = C.CTRL_CMD_DELMCAST_GRP | ||||||
|  | 	CTRL_CMD_GETMCAST_GRP      = C.CTRL_CMD_GETMCAST_GRP | ||||||
|  | 	CTRL_ATTR_UNSPEC           = C.CTRL_ATTR_UNSPEC | ||||||
|  | 	CTRL_ATTR_FAMILY_ID        = C.CTRL_ATTR_FAMILY_ID | ||||||
|  | 	CTRL_ATTR_FAMILY_NAME      = C.CTRL_ATTR_FAMILY_NAME | ||||||
|  | 	CTRL_ATTR_VERSION          = C.CTRL_ATTR_VERSION | ||||||
|  | 	CTRL_ATTR_HDRSIZE          = C.CTRL_ATTR_HDRSIZE | ||||||
|  | 	CTRL_ATTR_MAXATTR          = C.CTRL_ATTR_MAXATTR | ||||||
|  | 	CTRL_ATTR_OPS              = C.CTRL_ATTR_OPS | ||||||
|  | 	CTRL_ATTR_MCAST_GROUPS     = C.CTRL_ATTR_MCAST_GROUPS | ||||||
|  | 	CTRL_ATTR_OP_UNSPEC        = C.CTRL_ATTR_OP_UNSPEC | ||||||
|  | 	CTRL_ATTR_OP_ID            = C.CTRL_ATTR_OP_ID | ||||||
|  | 	CTRL_ATTR_OP_FLAGS         = C.CTRL_ATTR_OP_FLAGS | ||||||
|  | 	CTRL_ATTR_MCAST_GRP_UNSPEC = C.CTRL_ATTR_MCAST_GRP_UNSPEC | ||||||
|  | 	CTRL_ATTR_MCAST_GRP_NAME   = C.CTRL_ATTR_MCAST_GRP_NAME | ||||||
|  | 	CTRL_ATTR_MCAST_GRP_ID     = C.CTRL_ATTR_MCAST_GRP_ID | ||||||
|  | ) | ||||||
							
								
								
									
										81
									
								
								vendor/golang.org/x/sys/unix/mkpost.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										81
									
								
								vendor/golang.org/x/sys/unix/mkpost.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -8,10 +8,11 @@ | |||||||
| // modify the generated types. It is used to clean up | // modify the generated types. It is used to clean up | ||||||
| // the sys API in an architecture specific manner. | // the sys API in an architecture specific manner. | ||||||
| // | // | ||||||
| // mkpost is run after cgo -godefs by mkall.sh. | // mkpost is run after cgo -godefs; see README.md. | ||||||
| package main | package main | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"bytes" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"go/format" | 	"go/format" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| @@ -21,42 +22,72 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| func main() { | func main() { | ||||||
|  | 	// Get the OS and architecture (using GOARCH_TARGET if it exists) | ||||||
|  | 	goos := os.Getenv("GOOS") | ||||||
|  | 	goarch := os.Getenv("GOARCH_TARGET") | ||||||
|  | 	if goarch == "" { | ||||||
|  | 		goarch = os.Getenv("GOARCH") | ||||||
|  | 	} | ||||||
|  | 	// Check that we are using the new build system if we should be. | ||||||
|  | 	if goos == "linux" && goarch != "sparc64" { | ||||||
|  | 		if os.Getenv("GOLANG_SYS_BUILD") != "docker" { | ||||||
|  | 			os.Stderr.WriteString("In the new build system, mkpost should not be called directly.\n") | ||||||
|  | 			os.Stderr.WriteString("See README.md\n") | ||||||
|  | 			os.Exit(1) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	b, err := ioutil.ReadAll(os.Stdin) | 	b, err := ioutil.ReadAll(os.Stdin) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Fatal(err) | 		log.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	s := string(b) |  | ||||||
|  |  | ||||||
| 	goarch := os.Getenv("GOARCH") | 	// If we have empty Ptrace structs, we should delete them. Only s390x emits | ||||||
| 	goos := os.Getenv("GOOS") | 	// nonempty Ptrace structs. | ||||||
| 	if goarch == "s390x" && goos == "linux" { | 	ptraceRexexp := regexp.MustCompile(`type Ptrace((Psw|Fpregs|Per) struct {\s*})`) | ||||||
| 		// Export the types of PtraceRegs fields. | 	b = ptraceRexexp.ReplaceAll(b, nil) | ||||||
| 		re := regexp.MustCompile("ptrace(Psw|Fpregs|Per)") |  | ||||||
| 		s = re.ReplaceAllString(s, "Ptrace$1") |  | ||||||
|  |  | ||||||
| 		// Replace padding fields inserted by cgo with blank identifiers. |  | ||||||
| 		re = regexp.MustCompile("Pad_cgo[A-Za-z0-9_]*") |  | ||||||
| 		s = re.ReplaceAllString(s, "_") |  | ||||||
|  |  | ||||||
| 		// Replace other unwanted fields with blank identifiers. |  | ||||||
| 		re = regexp.MustCompile("X_[A-Za-z0-9_]*") |  | ||||||
| 		s = re.ReplaceAllString(s, "_") |  | ||||||
|  |  | ||||||
| 	// Replace the control_regs union with a blank identifier for now. | 	// Replace the control_regs union with a blank identifier for now. | ||||||
| 		re = regexp.MustCompile("(Control_regs)\\s+\\[0\\]uint64") | 	controlRegsRegex := regexp.MustCompile(`(Control_regs)\s+\[0\]uint64`) | ||||||
| 		s = re.ReplaceAllString(s, "_ [0]uint64") | 	b = controlRegsRegex.ReplaceAll(b, []byte("_ [0]uint64")) | ||||||
|  |  | ||||||
|  | 	// Remove fields that are added by glibc | ||||||
|  | 	// Note that this is unstable as the identifers are private. | ||||||
|  | 	removeFieldsRegex := regexp.MustCompile(`X__glibc\S*`) | ||||||
|  | 	b = removeFieldsRegex.ReplaceAll(b, []byte("_")) | ||||||
|  |  | ||||||
|  | 	// Convert [65]int8 to [65]byte in Utsname members to simplify | ||||||
|  | 	// conversion to string; see golang.org/issue/20753 | ||||||
|  | 	convertUtsnameRegex := regexp.MustCompile(`((Sys|Node|Domain)name|Release|Version|Machine)(\s+)\[(\d+)\]u?int8`) | ||||||
|  | 	b = convertUtsnameRegex.ReplaceAll(b, []byte("$1$3[$4]byte")) | ||||||
|  |  | ||||||
|  | 	// We refuse to export private fields on s390x | ||||||
|  | 	if goarch == "s390x" && goos == "linux" { | ||||||
|  | 		// Remove cgo padding fields | ||||||
|  | 		removeFieldsRegex := regexp.MustCompile(`Pad_cgo_\d+`) | ||||||
|  | 		b = removeFieldsRegex.ReplaceAll(b, []byte("_")) | ||||||
|  |  | ||||||
|  | 		// Remove padding, hidden, or unused fields | ||||||
|  | 		removeFieldsRegex = regexp.MustCompile(`X_\S+`) | ||||||
|  | 		b = removeFieldsRegex.ReplaceAll(b, []byte("_")) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// Remove the first line of warning from cgo | ||||||
|  | 	b = b[bytes.IndexByte(b, '\n')+1:] | ||||||
|  | 	// Modify the command in the header to include: | ||||||
|  | 	//  mkpost, our own warning, and a build tag. | ||||||
|  | 	replacement := fmt.Sprintf(`$1 | go run mkpost.go | ||||||
|  | // Code generated by the command above; see README.md. DO NOT EDIT. | ||||||
|  |  | ||||||
|  | // +build %s,%s`, goarch, goos) | ||||||
|  | 	cgoCommandRegex := regexp.MustCompile(`(cgo -godefs .*)`) | ||||||
|  | 	b = cgoCommandRegex.ReplaceAll(b, []byte(replacement)) | ||||||
|  |  | ||||||
| 	// gofmt | 	// gofmt | ||||||
| 	b, err = format.Source([]byte(s)) | 	b, err = format.Source(b) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Fatal(err) | 		log.Fatal(err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Append this command to the header to show where the new file | 	os.Stdout.Write(b) | ||||||
| 	// came from. |  | ||||||
| 	re := regexp.MustCompile("(cgo -godefs [a-zA-Z0-9_]+\\.go.*)") |  | ||||||
| 	b = re.ReplaceAll(b, []byte("$1 | go run mkpost.go")) |  | ||||||
|  |  | ||||||
| 	fmt.Printf("%s", b) |  | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								vendor/golang.org/x/sys/unix/pagesize_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/golang.org/x/sys/unix/pagesize_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | // Copyright 2017 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. | ||||||
|  |  | ||||||
|  | // +build darwin dragonfly freebsd linux netbsd openbsd solaris | ||||||
|  |  | ||||||
|  | // For Unix, get the pagesize from the runtime. | ||||||
|  |  | ||||||
|  | package unix | ||||||
|  |  | ||||||
|  | import "syscall" | ||||||
|  |  | ||||||
|  | func Getpagesize() int { | ||||||
|  | 	return syscall.Getpagesize() | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								vendor/golang.org/x/sys/unix/sockcmsg_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/golang.org/x/sys/unix/sockcmsg_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -13,9 +13,10 @@ import "unsafe" | |||||||
| // Round the length of a raw sockaddr up to align it properly. | // Round the length of a raw sockaddr up to align it properly. | ||||||
| func cmsgAlignOf(salen int) int { | func cmsgAlignOf(salen int) int { | ||||||
| 	salign := sizeofPtr | 	salign := sizeofPtr | ||||||
| 	// NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels | 	// NOTE: It seems like 64-bit Darwin, DragonFly BSD and | ||||||
| 	// still require 32-bit aligned access to network subsystem. | 	// Solaris kernels still require 32-bit aligned access to | ||||||
| 	if darwin64Bit || dragonfly64Bit { | 	// network subsystem. | ||||||
|  | 	if darwin64Bit || dragonfly64Bit || solaris64Bit { | ||||||
| 		salign = 4 | 		salign = 4 | ||||||
| 	} | 	} | ||||||
| 	return (salen + salign - 1) & ^(salign - 1) | 	return (salen + salign - 1) & ^(salign - 1) | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								vendor/golang.org/x/sys/unix/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/golang.org/x/sys/unix/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -49,21 +49,3 @@ func BytePtrFromString(s string) (*byte, error) { | |||||||
| // Single-word zero for use when we need a valid pointer to 0 bytes. | // Single-word zero for use when we need a valid pointer to 0 bytes. | ||||||
| // See mkunix.pl. | // See mkunix.pl. | ||||||
| var _zero uintptr | var _zero uintptr | ||||||
|  |  | ||||||
| func (ts *Timespec) Unix() (sec int64, nsec int64) { |  | ||||||
| 	return int64(ts.Sec), int64(ts.Nsec) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (tv *Timeval) Unix() (sec int64, nsec int64) { |  | ||||||
| 	return int64(tv.Sec), int64(tv.Usec) * 1000 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (ts *Timespec) Nano() int64 { |  | ||||||
| 	return int64(ts.Sec)*1e9 + int64(ts.Nsec) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (tv *Timeval) Nano() int64 { |  | ||||||
| 	return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 } |  | ||||||
|   | |||||||
							
								
								
									
										49
									
								
								vendor/golang.org/x/sys/unix/syscall_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								vendor/golang.org/x/sys/unix/syscall_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -561,13 +561,24 @@ func Utimes(path string, tv []Timeval) error { | |||||||
|  |  | ||||||
| func UtimesNano(path string, ts []Timespec) error { | func UtimesNano(path string, ts []Timespec) error { | ||||||
| 	if ts == nil { | 	if ts == nil { | ||||||
|  | 		err := utimensat(AT_FDCWD, path, nil, 0) | ||||||
|  | 		if err != ENOSYS { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 		return utimes(path, nil) | 		return utimes(path, nil) | ||||||
| 	} | 	} | ||||||
| 	// TODO: The BSDs can do utimensat with SYS_UTIMENSAT but it |  | ||||||
| 	// isn't supported by darwin so this uses utimes instead |  | ||||||
| 	if len(ts) != 2 { | 	if len(ts) != 2 { | ||||||
| 		return EINVAL | 		return EINVAL | ||||||
| 	} | 	} | ||||||
|  | 	// Darwin setattrlist can set nanosecond timestamps | ||||||
|  | 	err := setattrlistTimes(path, ts, 0) | ||||||
|  | 	if err != ENOSYS { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	err = utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0) | ||||||
|  | 	if err != ENOSYS { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
| 	// Not as efficient as it could be because Timespec and | 	// Not as efficient as it could be because Timespec and | ||||||
| 	// Timeval have different types in the different OSes | 	// Timeval have different types in the different OSes | ||||||
| 	tv := [2]Timeval{ | 	tv := [2]Timeval{ | ||||||
| @@ -577,6 +588,20 @@ func UtimesNano(path string, ts []Timespec) error { | |||||||
| 	return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) | 	return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0]))) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error { | ||||||
|  | 	if ts == nil { | ||||||
|  | 		return utimensat(dirfd, path, nil, flags) | ||||||
|  | 	} | ||||||
|  | 	if len(ts) != 2 { | ||||||
|  | 		return EINVAL | ||||||
|  | 	} | ||||||
|  | 	err := setattrlistTimes(path, ts, flags) | ||||||
|  | 	if err != ENOSYS { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags) | ||||||
|  | } | ||||||
|  |  | ||||||
| //sys	futimes(fd int, timeval *[2]Timeval) (err error) | //sys	futimes(fd int, timeval *[2]Timeval) (err error) | ||||||
|  |  | ||||||
| func Futimes(fd int, tv []Timeval) error { | func Futimes(fd int, tv []Timeval) error { | ||||||
| @@ -591,12 +616,18 @@ func Futimes(fd int, tv []Timeval) error { | |||||||
|  |  | ||||||
| //sys	fcntl(fd int, cmd int, arg int) (val int, err error) | //sys	fcntl(fd int, cmd int, arg int) (val int, err error) | ||||||
|  |  | ||||||
|  | //sys   poll(fds *PollFd, nfds int, timeout int) (n int, err error) | ||||||
|  |  | ||||||
|  | func Poll(fds []PollFd, timeout int) (n int, err error) { | ||||||
|  | 	if len(fds) == 0 { | ||||||
|  | 		return poll(nil, 0, timeout) | ||||||
|  | 	} | ||||||
|  | 	return poll(&fds[0], len(fds), timeout) | ||||||
|  | } | ||||||
|  |  | ||||||
| // TODO: wrap | // TODO: wrap | ||||||
| //	Acct(name nil-string) (err error) | //	Acct(name nil-string) (err error) | ||||||
| //	Gethostuuid(uuid *byte, timeout *Timespec) (err error) | //	Gethostuuid(uuid *byte, timeout *Timespec) (err error) | ||||||
| //	Madvise(addr *byte, len int, behav int) (err error) |  | ||||||
| //	Mprotect(addr *byte, len int, prot int) (err error) |  | ||||||
| //	Msync(addr *byte, len int, flags int) (err error) |  | ||||||
| //	Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, err error) | //	Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, err error) | ||||||
|  |  | ||||||
| var mapper = &mmapper{ | var mapper = &mmapper{ | ||||||
| @@ -612,3 +643,11 @@ func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, e | |||||||
| func Munmap(b []byte) (err error) { | func Munmap(b []byte) (err error) { | ||||||
| 	return mapper.Munmap(b) | 	return mapper.Munmap(b) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //sys	Madvise(b []byte, behav int) (err error) | ||||||
|  | //sys	Mlock(b []byte) (err error) | ||||||
|  | //sys	Mlockall(flags int) (err error) | ||||||
|  | //sys	Mprotect(b []byte, prot int) (err error) | ||||||
|  | //sys	Msync(b []byte, flags int) (err error) | ||||||
|  | //sys	Munlock(b []byte) (err error) | ||||||
|  | //sys	Munlockall() (err error) | ||||||
|   | |||||||
							
								
								
									
										179
									
								
								vendor/golang.org/x/sys/unix/syscall_darwin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										179
									
								
								vendor/golang.org/x/sys/unix/syscall_darwin.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -76,32 +76,16 @@ func nametomib(name string) (mib []_C_int, err error) { | |||||||
| 	return buf[0 : n/siz], nil | 	return buf[0 : n/siz], nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // ParseDirent parses up to max directory entries in buf, | func direntIno(buf []byte) (uint64, bool) { | ||||||
| // appending the names to names.  It returns the number | 	return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) | ||||||
| // bytes consumed from buf, the number of entries added | } | ||||||
| // to names, and the new names slice. |  | ||||||
| func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { | func direntReclen(buf []byte) (uint64, bool) { | ||||||
| 	origlen := len(buf) | 	return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) | ||||||
| 	for max != 0 && len(buf) > 0 { | } | ||||||
| 		dirent := (*Dirent)(unsafe.Pointer(&buf[0])) |  | ||||||
| 		if dirent.Reclen == 0 { | func direntNamlen(buf []byte) (uint64, bool) { | ||||||
| 			buf = nil | 	return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 		buf = buf[dirent.Reclen:] |  | ||||||
| 		if dirent.Ino == 0 { // File absent in directory. |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0])) |  | ||||||
| 		var name = string(bytes[0:dirent.Namlen]) |  | ||||||
| 		if name == "." || name == ".." { // Useless names |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		max-- |  | ||||||
| 		count++ |  | ||||||
| 		names = append(names, name) |  | ||||||
| 	} |  | ||||||
| 	return origlen - len(buf), count, names |  | ||||||
| } | } | ||||||
|  |  | ||||||
| //sys   ptrace(request int, pid int, addr uintptr, data uintptr) (err error) | //sys   ptrace(request int, pid int, addr uintptr, data uintptr) (err error) | ||||||
| @@ -203,6 +187,42 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func setattrlistTimes(path string, times []Timespec, flags int) error { | ||||||
|  | 	_p0, err := BytePtrFromString(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var attrList attrList | ||||||
|  | 	attrList.bitmapCount = ATTR_BIT_MAP_COUNT | ||||||
|  | 	attrList.CommonAttr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME | ||||||
|  |  | ||||||
|  | 	// order is mtime, atime: the opposite of Chtimes | ||||||
|  | 	attributes := [2]Timespec{times[1], times[0]} | ||||||
|  | 	options := 0 | ||||||
|  | 	if flags&AT_SYMLINK_NOFOLLOW != 0 { | ||||||
|  | 		options |= FSOPT_NOFOLLOW | ||||||
|  | 	} | ||||||
|  | 	_, _, e1 := Syscall6( | ||||||
|  | 		SYS_SETATTRLIST, | ||||||
|  | 		uintptr(unsafe.Pointer(_p0)), | ||||||
|  | 		uintptr(unsafe.Pointer(&attrList)), | ||||||
|  | 		uintptr(unsafe.Pointer(&attributes)), | ||||||
|  | 		uintptr(unsafe.Sizeof(attributes)), | ||||||
|  | 		uintptr(options), | ||||||
|  | 		0, | ||||||
|  | 	) | ||||||
|  | 	if e1 != 0 { | ||||||
|  | 		return e1 | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func utimensat(dirfd int, path string, times *[2]Timespec, flags int) error { | ||||||
|  | 	// Darwin doesn't support SYS_UTIMENSAT | ||||||
|  | 	return ENOSYS | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Wrapped |  * Wrapped | ||||||
|  */ |  */ | ||||||
| @@ -211,6 +231,91 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | |||||||
|  |  | ||||||
| func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(signum), 1) } | func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(signum), 1) } | ||||||
|  |  | ||||||
|  | //sys	ioctl(fd int, req uint, arg uintptr) (err error) | ||||||
|  |  | ||||||
|  | // ioctl itself should not be exposed directly, but additional get/set | ||||||
|  | // functions for specific types are permissible. | ||||||
|  |  | ||||||
|  | // IoctlSetInt performs an ioctl operation which sets an integer value | ||||||
|  | // on fd, using the specified request number. | ||||||
|  | func IoctlSetInt(fd int, req uint, value int) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(value)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlSetWinsize(fd int, req uint, value *Winsize) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(unsafe.Pointer(value))) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlSetTermios(fd int, req uint, value *Termios) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(unsafe.Pointer(value))) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IoctlGetInt performs an ioctl operation which gets an integer value | ||||||
|  | // from fd, using the specified request number. | ||||||
|  | func IoctlGetInt(fd int, req uint) (int, error) { | ||||||
|  | 	var value int | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return value, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlGetWinsize(fd int, req uint) (*Winsize, error) { | ||||||
|  | 	var value Winsize | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return &value, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlGetTermios(fd int, req uint) (*Termios, error) { | ||||||
|  | 	var value Termios | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return &value, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Uname(uname *Utsname) error { | ||||||
|  | 	mib := []_C_int{CTL_KERN, KERN_OSTYPE} | ||||||
|  | 	n := unsafe.Sizeof(uname.Sysname) | ||||||
|  | 	if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mib = []_C_int{CTL_KERN, KERN_HOSTNAME} | ||||||
|  | 	n = unsafe.Sizeof(uname.Nodename) | ||||||
|  | 	if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mib = []_C_int{CTL_KERN, KERN_OSRELEASE} | ||||||
|  | 	n = unsafe.Sizeof(uname.Release) | ||||||
|  | 	if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mib = []_C_int{CTL_KERN, KERN_VERSION} | ||||||
|  | 	n = unsafe.Sizeof(uname.Version) | ||||||
|  | 	if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// The version might have newlines or tabs in it, convert them to | ||||||
|  | 	// spaces. | ||||||
|  | 	for i, b := range uname.Version { | ||||||
|  | 		if b == '\n' || b == '\t' { | ||||||
|  | 			if i == len(uname.Version)-1 { | ||||||
|  | 				uname.Version[i] = 0 | ||||||
|  | 			} else { | ||||||
|  | 				uname.Version[i] = ' ' | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mib = []_C_int{CTL_HW, HW_MACHINE} | ||||||
|  | 	n = unsafe.Sizeof(uname.Machine) | ||||||
|  | 	if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Exposed directly |  * Exposed directly | ||||||
|  */ |  */ | ||||||
| @@ -226,10 +331,13 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig | |||||||
| //sys	Dup2(from int, to int) (err error) | //sys	Dup2(from int, to int) (err error) | ||||||
| //sys	Exchangedata(path1 string, path2 string, options int) (err error) | //sys	Exchangedata(path1 string, path2 string, options int) (err error) | ||||||
| //sys	Exit(code int) | //sys	Exit(code int) | ||||||
|  | //sys	Faccessat(dirfd int, path string, mode uint32, flags int) (err error) | ||||||
| //sys	Fchdir(fd int) (err error) | //sys	Fchdir(fd int) (err error) | ||||||
| //sys	Fchflags(fd int, flags int) (err error) | //sys	Fchflags(fd int, flags int) (err error) | ||||||
| //sys	Fchmod(fd int, mode uint32) (err error) | //sys	Fchmod(fd int, mode uint32) (err error) | ||||||
|  | //sys	Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) | ||||||
| //sys	Fchown(fd int, uid int, gid int) (err error) | //sys	Fchown(fd int, uid int, gid int) (err error) | ||||||
|  | //sys	Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) | ||||||
| //sys	Flock(fd int, how int) (err error) | //sys	Flock(fd int, how int) (err error) | ||||||
| //sys	Fpathconf(fd int, name int) (val int, err error) | //sys	Fpathconf(fd int, name int) (val int, err error) | ||||||
| //sys	Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 | //sys	Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 | ||||||
| @@ -254,23 +362,23 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig | |||||||
| //sys	Kqueue() (fd int, err error) | //sys	Kqueue() (fd int, err error) | ||||||
| //sys	Lchown(path string, uid int, gid int) (err error) | //sys	Lchown(path string, uid int, gid int) (err error) | ||||||
| //sys	Link(path string, link string) (err error) | //sys	Link(path string, link string) (err error) | ||||||
|  | //sys	Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) | ||||||
| //sys	Listen(s int, backlog int) (err error) | //sys	Listen(s int, backlog int) (err error) | ||||||
| //sys	Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 | //sys	Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 | ||||||
| //sys	Mkdir(path string, mode uint32) (err error) | //sys	Mkdir(path string, mode uint32) (err error) | ||||||
|  | //sys	Mkdirat(dirfd int, path string, mode uint32) (err error) | ||||||
| //sys	Mkfifo(path string, mode uint32) (err error) | //sys	Mkfifo(path string, mode uint32) (err error) | ||||||
| //sys	Mknod(path string, mode uint32, dev int) (err error) | //sys	Mknod(path string, mode uint32, dev int) (err error) | ||||||
| //sys	Mlock(b []byte) (err error) |  | ||||||
| //sys	Mlockall(flags int) (err error) |  | ||||||
| //sys	Mprotect(b []byte, prot int) (err error) |  | ||||||
| //sys	Munlock(b []byte) (err error) |  | ||||||
| //sys	Munlockall() (err error) |  | ||||||
| //sys	Open(path string, mode int, perm uint32) (fd int, err error) | //sys	Open(path string, mode int, perm uint32) (fd int, err error) | ||||||
|  | //sys	Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error) | ||||||
| //sys	Pathconf(path string, name int) (val int, err error) | //sys	Pathconf(path string, name int) (val int, err error) | ||||||
| //sys	Pread(fd int, p []byte, offset int64) (n int, err error) | //sys	Pread(fd int, p []byte, offset int64) (n int, err error) | ||||||
| //sys	Pwrite(fd int, p []byte, offset int64) (n int, err error) | //sys	Pwrite(fd int, p []byte, offset int64) (n int, err error) | ||||||
| //sys	read(fd int, p []byte) (n int, err error) | //sys	read(fd int, p []byte) (n int, err error) | ||||||
| //sys	Readlink(path string, buf []byte) (n int, err error) | //sys	Readlink(path string, buf []byte) (n int, err error) | ||||||
|  | //sys	Readlinkat(dirfd int, path string, buf []byte) (n int, err error) | ||||||
| //sys	Rename(from string, to string) (err error) | //sys	Rename(from string, to string) (err error) | ||||||
|  | //sys	Renameat(fromfd int, from string, tofd int, to string) (err error) | ||||||
| //sys	Revoke(path string) (err error) | //sys	Revoke(path string) (err error) | ||||||
| //sys	Rmdir(path string) (err error) | //sys	Rmdir(path string) (err error) | ||||||
| //sys	Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK | //sys	Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK | ||||||
| @@ -291,11 +399,13 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig | |||||||
| //sys	Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 | //sys	Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 | ||||||
| //sys	Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64 | //sys	Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64 | ||||||
| //sys	Symlink(path string, link string) (err error) | //sys	Symlink(path string, link string) (err error) | ||||||
|  | //sys	Symlinkat(oldpath string, newdirfd int, newpath string) (err error) | ||||||
| //sys	Sync() (err error) | //sys	Sync() (err error) | ||||||
| //sys	Truncate(path string, length int64) (err error) | //sys	Truncate(path string, length int64) (err error) | ||||||
| //sys	Umask(newmask int) (oldmask int) | //sys	Umask(newmask int) (oldmask int) | ||||||
| //sys	Undelete(path string) (err error) | //sys	Undelete(path string) (err error) | ||||||
| //sys	Unlink(path string) (err error) | //sys	Unlink(path string) (err error) | ||||||
|  | //sys	Unlinkat(dirfd int, path string, flags int) (err error) | ||||||
| //sys	Unmount(path string, flags int) (err error) | //sys	Unmount(path string, flags int) (err error) | ||||||
| //sys	write(fd int, p []byte) (n int, err error) | //sys	write(fd int, p []byte) (n int, err error) | ||||||
| //sys   mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) | //sys   mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) | ||||||
| @@ -335,9 +445,6 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig | |||||||
| // Add_profil | // Add_profil | ||||||
| // Kdebug_trace | // Kdebug_trace | ||||||
| // Sigreturn | // Sigreturn | ||||||
| // Mmap |  | ||||||
| // Mlock |  | ||||||
| // Munlock |  | ||||||
| // Atsocket | // Atsocket | ||||||
| // Kqueue_from_portset_np | // Kqueue_from_portset_np | ||||||
| // Kqueue_portset | // Kqueue_portset | ||||||
| @@ -347,7 +454,6 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig | |||||||
| // Searchfs | // Searchfs | ||||||
| // Delete | // Delete | ||||||
| // Copyfile | // Copyfile | ||||||
| // Poll |  | ||||||
| // Watchevent | // Watchevent | ||||||
| // Waitevent | // Waitevent | ||||||
| // Modwatch | // Modwatch | ||||||
| @@ -430,8 +536,6 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig | |||||||
| // Lio_listio | // Lio_listio | ||||||
| // __pthread_cond_wait | // __pthread_cond_wait | ||||||
| // Iopolicysys | // Iopolicysys | ||||||
| // Mlockall |  | ||||||
| // Munlockall |  | ||||||
| // __pthread_kill | // __pthread_kill | ||||||
| // __pthread_sigmask | // __pthread_sigmask | ||||||
| // __sigwait | // __sigwait | ||||||
| @@ -485,7 +589,6 @@ func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(sig | |||||||
| // Sendmsg_nocancel | // Sendmsg_nocancel | ||||||
| // Recvfrom_nocancel | // Recvfrom_nocancel | ||||||
| // Accept_nocancel | // Accept_nocancel | ||||||
| // Msync_nocancel |  | ||||||
| // Fcntl_nocancel | // Fcntl_nocancel | ||||||
| // Select_nocancel | // Select_nocancel | ||||||
| // Fsync_nocancel | // Fsync_nocancel | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_darwin_386.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_darwin_386.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,21 +11,12 @@ import ( | |||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func Getpagesize() int { return 4096 } | func setTimespec(sec, nsec int64) Timespec { | ||||||
|  | 	return Timespec{Sec: int32(sec), Nsec: int32(nsec)} | ||||||
| func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } |  | ||||||
|  |  | ||||||
| func NsecToTimespec(nsec int64) (ts Timespec) { |  | ||||||
| 	ts.Sec = int32(nsec / 1e9) |  | ||||||
| 	ts.Nsec = int32(nsec % 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NsecToTimeval(nsec int64) (tv Timeval) { | func setTimeval(sec, usec int64) Timeval { | ||||||
| 	nsec += 999 // round up to microsecond | 	return Timeval{Sec: int32(sec), Usec: int32(usec)} | ||||||
| 	tv.Usec = int32(nsec % 1e9 / 1e3) |  | ||||||
| 	tv.Sec = int32(nsec / 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| //sysnb	gettimeofday(tp *Timeval) (sec int32, usec int32, err error) | //sysnb	gettimeofday(tp *Timeval) (sec int32, usec int32, err error) | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,23 +11,12 @@ import ( | |||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| //sys	Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) | func setTimespec(sec, nsec int64) Timespec { | ||||||
|  | 	return Timespec{Sec: sec, Nsec: nsec} | ||||||
| func Getpagesize() int { return 4096 } |  | ||||||
|  |  | ||||||
| func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } |  | ||||||
|  |  | ||||||
| func NsecToTimespec(nsec int64) (ts Timespec) { |  | ||||||
| 	ts.Sec = nsec / 1e9 |  | ||||||
| 	ts.Nsec = nsec % 1e9 |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NsecToTimeval(nsec int64) (tv Timeval) { | func setTimeval(sec, usec int64) Timeval { | ||||||
| 	nsec += 999 // round up to microsecond | 	return Timeval{Sec: sec, Usec: int32(usec)} | ||||||
| 	tv.Usec = int32(nsec % 1e9 / 1e3) |  | ||||||
| 	tv.Sec = int64(nsec / 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| //sysnb	gettimeofday(tp *Timeval) (sec int64, usec int32, err error) | //sysnb	gettimeofday(tp *Timeval) (sec int64, usec int32, err error) | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								vendor/golang.org/x/sys/unix/syscall_darwin_arm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/golang.org/x/sys/unix/syscall_darwin_arm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -9,21 +9,12 @@ import ( | |||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func Getpagesize() int { return 4096 } | func setTimespec(sec, nsec int64) Timespec { | ||||||
|  | 	return Timespec{Sec: int32(sec), Nsec: int32(nsec)} | ||||||
| func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } |  | ||||||
|  |  | ||||||
| func NsecToTimespec(nsec int64) (ts Timespec) { |  | ||||||
| 	ts.Sec = int32(nsec / 1e9) |  | ||||||
| 	ts.Nsec = int32(nsec % 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NsecToTimeval(nsec int64) (tv Timeval) { | func setTimeval(sec, usec int64) Timeval { | ||||||
| 	nsec += 999 // round up to microsecond | 	return Timeval{Sec: int32(sec), Usec: int32(usec)} | ||||||
| 	tv.Usec = int32(nsec % 1e9 / 1e3) |  | ||||||
| 	tv.Sec = int32(nsec / 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| //sysnb	gettimeofday(tp *Timeval) (sec int32, usec int32, err error) | //sysnb	gettimeofday(tp *Timeval) (sec int32, usec int32, err error) | ||||||
| @@ -69,3 +60,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e | |||||||
| } | } | ||||||
|  |  | ||||||
| func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic | func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic | ||||||
|  |  | ||||||
|  | // SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions | ||||||
|  | // of darwin/arm the syscall is called sysctl instead of __sysctl. | ||||||
|  | const SYS___SYSCTL = SYS_SYSCTL | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,21 +11,12 @@ import ( | |||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func Getpagesize() int { return 16384 } | func setTimespec(sec, nsec int64) Timespec { | ||||||
|  | 	return Timespec{Sec: sec, Nsec: nsec} | ||||||
| func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } |  | ||||||
|  |  | ||||||
| func NsecToTimespec(nsec int64) (ts Timespec) { |  | ||||||
| 	ts.Sec = nsec / 1e9 |  | ||||||
| 	ts.Nsec = nsec % 1e9 |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NsecToTimeval(nsec int64) (tv Timeval) { | func setTimeval(sec, usec int64) Timeval { | ||||||
| 	nsec += 999 // round up to microsecond | 	return Timeval{Sec: sec, Usec: int32(usec)} | ||||||
| 	tv.Usec = int32(nsec % 1e9 / 1e3) |  | ||||||
| 	tv.Sec = int64(nsec / 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| //sysnb	gettimeofday(tp *Timeval) (sec int64, usec int32, err error) | //sysnb	gettimeofday(tp *Timeval) (sec int64, usec int32, err error) | ||||||
|   | |||||||
							
								
								
									
										113
									
								
								vendor/golang.org/x/sys/unix/syscall_dragonfly.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										113
									
								
								vendor/golang.org/x/sys/unix/syscall_dragonfly.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,8 +1,8 @@ | |||||||
| // Copyright 2009,2010 The Go Authors. All rights reserved. | // Copyright 2009 The Go Authors. All rights reserved. | ||||||
| // Use of this source code is governed by a BSD-style | // Use of this source code is governed by a BSD-style | ||||||
| // license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
| // FreeBSD system calls. | // DragonFly BSD system calls. | ||||||
| // This file is compiled as ordinary Go code, | // This file is compiled as ordinary Go code, | ||||||
| // but it is also input to mksyscall, | // but it is also input to mksyscall, | ||||||
| // which parses the //sys lines and generates system call stubs. | // which parses the //sys lines and generates system call stubs. | ||||||
| @@ -56,29 +56,20 @@ func nametomib(name string) (mib []_C_int, err error) { | |||||||
| 	return buf[0 : n/siz], nil | 	return buf[0 : n/siz], nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // ParseDirent parses up to max directory entries in buf, | func direntIno(buf []byte) (uint64, bool) { | ||||||
| // appending the names to names.  It returns the number | 	return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno)) | ||||||
| // bytes consumed from buf, the number of entries added | } | ||||||
| // to names, and the new names slice. |  | ||||||
| func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { | func direntReclen(buf []byte) (uint64, bool) { | ||||||
| 	origlen := len(buf) | 	namlen, ok := direntNamlen(buf) | ||||||
| 	for max != 0 && len(buf) > 0 { | 	if !ok { | ||||||
| 		dirent := (*Dirent)(unsafe.Pointer(&buf[0])) | 		return 0, false | ||||||
| 		reclen := int(16+dirent.Namlen+1+7) & ^7 |  | ||||||
| 		buf = buf[reclen:] |  | ||||||
| 		if dirent.Fileno == 0 { // File absent in directory. |  | ||||||
| 			continue |  | ||||||
| 	} | 	} | ||||||
| 		bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0])) | 	return (16 + namlen + 1 + 7) &^ 7, true | ||||||
| 		var name = string(bytes[0:dirent.Namlen]) | } | ||||||
| 		if name == "." || name == ".." { // Useless names |  | ||||||
| 			continue | func direntNamlen(buf []byte) (uint64, bool) { | ||||||
| 		} | 	return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) | ||||||
| 		max-- |  | ||||||
| 		count++ |  | ||||||
| 		names = append(names, name) |  | ||||||
| 	} |  | ||||||
| 	return origlen - len(buf), count, names |  | ||||||
| } | } | ||||||
|  |  | ||||||
| //sysnb pipe() (r int, w int, err error) | //sysnb pipe() (r int, w int, err error) | ||||||
| @@ -101,6 +92,24 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { | |||||||
| 	return extpwrite(fd, p, 0, offset) | 	return extpwrite(fd, p, 0, offset) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) { | ||||||
|  | 	var rsa RawSockaddrAny | ||||||
|  | 	var len _Socklen = SizeofSockaddrAny | ||||||
|  | 	nfd, err = accept4(fd, &rsa, &len, flags) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if len > SizeofSockaddrAny { | ||||||
|  | 		panic("RawSockaddrAny too small") | ||||||
|  | 	} | ||||||
|  | 	sa, err = anyToSockaddr(&rsa) | ||||||
|  | 	if err != nil { | ||||||
|  | 		Close(nfd) | ||||||
|  | 		nfd = 0 | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
| func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | ||||||
| 	var _p0 unsafe.Pointer | 	var _p0 unsafe.Pointer | ||||||
| 	var bufsize uintptr | 	var bufsize uintptr | ||||||
| @@ -116,6 +125,50 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func setattrlistTimes(path string, times []Timespec, flags int) error { | ||||||
|  | 	// used on Darwin for UtimesNano | ||||||
|  | 	return ENOSYS | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //sys	ioctl(fd int, req uint, arg uintptr) (err error) | ||||||
|  |  | ||||||
|  | // ioctl itself should not be exposed directly, but additional get/set | ||||||
|  | // functions for specific types are permissible. | ||||||
|  |  | ||||||
|  | // IoctlSetInt performs an ioctl operation which sets an integer value | ||||||
|  | // on fd, using the specified request number. | ||||||
|  | func IoctlSetInt(fd int, req uint, value int) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(value)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlSetWinsize(fd int, req uint, value *Winsize) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(unsafe.Pointer(value))) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlSetTermios(fd int, req uint, value *Termios) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(unsafe.Pointer(value))) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IoctlGetInt performs an ioctl operation which gets an integer value | ||||||
|  | // from fd, using the specified request number. | ||||||
|  | func IoctlGetInt(fd int, req uint) (int, error) { | ||||||
|  | 	var value int | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return value, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlGetWinsize(fd int, req uint) (*Winsize, error) { | ||||||
|  | 	var value Winsize | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return &value, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlGetTermios(fd int, req uint) (*Termios, error) { | ||||||
|  | 	var value Termios | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return &value, err | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Exposed directly |  * Exposed directly | ||||||
|  */ |  */ | ||||||
| @@ -165,11 +218,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | |||||||
| //sys	Mkdir(path string, mode uint32) (err error) | //sys	Mkdir(path string, mode uint32) (err error) | ||||||
| //sys	Mkfifo(path string, mode uint32) (err error) | //sys	Mkfifo(path string, mode uint32) (err error) | ||||||
| //sys	Mknod(path string, mode uint32, dev int) (err error) | //sys	Mknod(path string, mode uint32, dev int) (err error) | ||||||
| //sys	Mlock(b []byte) (err error) |  | ||||||
| //sys	Mlockall(flags int) (err error) |  | ||||||
| //sys	Mprotect(b []byte, prot int) (err error) |  | ||||||
| //sys	Munlock(b []byte) (err error) |  | ||||||
| //sys	Munlockall() (err error) |  | ||||||
| //sys	Nanosleep(time *Timespec, leftover *Timespec) (err error) | //sys	Nanosleep(time *Timespec, leftover *Timespec) (err error) | ||||||
| //sys	Open(path string, mode int, perm uint32) (fd int, err error) | //sys	Open(path string, mode int, perm uint32) (fd int, err error) | ||||||
| //sys	Pathconf(path string, name int) (val int, err error) | //sys	Pathconf(path string, name int) (val int, err error) | ||||||
| @@ -208,6 +256,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | |||||||
| //sys   munmap(addr uintptr, length uintptr) (err error) | //sys   munmap(addr uintptr, length uintptr) (err error) | ||||||
| //sys	readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ | //sys	readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ | ||||||
| //sys	writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE | //sys	writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE | ||||||
|  | //sys	accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) | ||||||
|  | //sys	utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Unimplemented |  * Unimplemented | ||||||
| @@ -219,7 +269,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | |||||||
| // Getlogin | // Getlogin | ||||||
| // Sigpending | // Sigpending | ||||||
| // Sigaltstack | // Sigaltstack | ||||||
| // Ioctl |  | ||||||
| // Reboot | // Reboot | ||||||
| // Execve | // Execve | ||||||
| // Vfork | // Vfork | ||||||
| @@ -242,7 +291,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | |||||||
| // Add_profil | // Add_profil | ||||||
| // Kdebug_trace | // Kdebug_trace | ||||||
| // Sigreturn | // Sigreturn | ||||||
| // Mmap |  | ||||||
| // Atsocket | // Atsocket | ||||||
| // Kqueue_from_portset_np | // Kqueue_from_portset_np | ||||||
| // Kqueue_portset | // Kqueue_portset | ||||||
| @@ -252,7 +300,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | |||||||
| // Searchfs | // Searchfs | ||||||
| // Delete | // Delete | ||||||
| // Copyfile | // Copyfile | ||||||
| // Poll |  | ||||||
| // Watchevent | // Watchevent | ||||||
| // Waitevent | // Waitevent | ||||||
| // Modwatch | // Modwatch | ||||||
| @@ -387,7 +434,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | |||||||
| // Sendmsg_nocancel | // Sendmsg_nocancel | ||||||
| // Recvfrom_nocancel | // Recvfrom_nocancel | ||||||
| // Accept_nocancel | // Accept_nocancel | ||||||
| // Msync_nocancel |  | ||||||
| // Fcntl_nocancel | // Fcntl_nocancel | ||||||
| // Select_nocancel | // Select_nocancel | ||||||
| // Fsync_nocancel | // Fsync_nocancel | ||||||
| @@ -399,7 +445,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | |||||||
| // Pread_nocancel | // Pread_nocancel | ||||||
| // Pwrite_nocancel | // Pwrite_nocancel | ||||||
| // Waitid_nocancel | // Waitid_nocancel | ||||||
| // Poll_nocancel |  | ||||||
| // Msgsnd_nocancel | // Msgsnd_nocancel | ||||||
| // Msgrcv_nocancel | // Msgrcv_nocancel | ||||||
| // Sem_wait_nocancel | // Sem_wait_nocancel | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,21 +11,12 @@ import ( | |||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func Getpagesize() int { return 4096 } | func setTimespec(sec, nsec int64) Timespec { | ||||||
|  | 	return Timespec{Sec: sec, Nsec: nsec} | ||||||
| func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } |  | ||||||
|  |  | ||||||
| func NsecToTimespec(nsec int64) (ts Timespec) { |  | ||||||
| 	ts.Sec = nsec / 1e9 |  | ||||||
| 	ts.Nsec = nsec % 1e9 |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NsecToTimeval(nsec int64) (tv Timeval) { | func setTimeval(sec, usec int64) Timeval { | ||||||
| 	nsec += 999 // round up to microsecond | 	return Timeval{Sec: sec, Usec: usec} | ||||||
| 	tv.Usec = nsec % 1e9 / 1e3 |  | ||||||
| 	tv.Sec = int64(nsec / 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func SetKevent(k *Kevent_t, fd, mode, flags int) { | func SetKevent(k *Kevent_t, fd, mode, flags int) { | ||||||
|   | |||||||
							
								
								
									
										153
									
								
								vendor/golang.org/x/sys/unix/syscall_freebsd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										153
									
								
								vendor/golang.org/x/sys/unix/syscall_freebsd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -54,32 +54,16 @@ func nametomib(name string) (mib []_C_int, err error) { | |||||||
| 	return buf[0 : n/siz], nil | 	return buf[0 : n/siz], nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // ParseDirent parses up to max directory entries in buf, | func direntIno(buf []byte) (uint64, bool) { | ||||||
| // appending the names to names.  It returns the number | 	return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno)) | ||||||
| // bytes consumed from buf, the number of entries added | } | ||||||
| // to names, and the new names slice. |  | ||||||
| func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { | func direntReclen(buf []byte) (uint64, bool) { | ||||||
| 	origlen := len(buf) | 	return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) | ||||||
| 	for max != 0 && len(buf) > 0 { | } | ||||||
| 		dirent := (*Dirent)(unsafe.Pointer(&buf[0])) |  | ||||||
| 		if dirent.Reclen == 0 { | func direntNamlen(buf []byte) (uint64, bool) { | ||||||
| 			buf = nil | 	return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 		buf = buf[dirent.Reclen:] |  | ||||||
| 		if dirent.Fileno == 0 { // File absent in directory. |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0])) |  | ||||||
| 		var name = string(bytes[0:dirent.Namlen]) |  | ||||||
| 		if name == "." || name == ".." { // Useless names |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		max-- |  | ||||||
| 		count++ |  | ||||||
| 		names = append(names, name) |  | ||||||
| 	} |  | ||||||
| 	return origlen - len(buf), count, names |  | ||||||
| } | } | ||||||
|  |  | ||||||
| //sysnb pipe() (r int, w int, err error) | //sysnb pipe() (r int, w int, err error) | ||||||
| @@ -136,6 +120,11 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func setattrlistTimes(path string, times []Timespec, flags int) error { | ||||||
|  | 	// used on Darwin for UtimesNano | ||||||
|  | 	return ENOSYS | ||||||
|  | } | ||||||
|  |  | ||||||
| // Derive extattr namespace and attribute name | // Derive extattr namespace and attribute name | ||||||
|  |  | ||||||
| func xattrnamespace(fullattr string) (ns int, attr string, err error) { | func xattrnamespace(fullattr string) (ns int, attr string, err error) { | ||||||
| @@ -368,11 +357,99 @@ func Llistxattr(link string, dest []byte) (sz int, err error) { | |||||||
| 	return s, e | 	return s, e | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //sys   ioctl(fd int, req uint, arg uintptr) (err error) | ||||||
|  |  | ||||||
|  | // ioctl itself should not be exposed directly, but additional get/set | ||||||
|  | // functions for specific types are permissible. | ||||||
|  |  | ||||||
|  | // IoctlSetInt performs an ioctl operation which sets an integer value | ||||||
|  | // on fd, using the specified request number. | ||||||
|  | func IoctlSetInt(fd int, req uint, value int) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(value)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlSetWinsize(fd int, req uint, value *Winsize) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(unsafe.Pointer(value))) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlSetTermios(fd int, req uint, value *Termios) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(unsafe.Pointer(value))) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IoctlGetInt performs an ioctl operation which gets an integer value | ||||||
|  | // from fd, using the specified request number. | ||||||
|  | func IoctlGetInt(fd int, req uint) (int, error) { | ||||||
|  | 	var value int | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return value, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlGetWinsize(fd int, req uint) (*Winsize, error) { | ||||||
|  | 	var value Winsize | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return &value, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlGetTermios(fd int, req uint) (*Termios, error) { | ||||||
|  | 	var value Termios | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return &value, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Uname(uname *Utsname) error { | ||||||
|  | 	mib := []_C_int{CTL_KERN, KERN_OSTYPE} | ||||||
|  | 	n := unsafe.Sizeof(uname.Sysname) | ||||||
|  | 	if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mib = []_C_int{CTL_KERN, KERN_HOSTNAME} | ||||||
|  | 	n = unsafe.Sizeof(uname.Nodename) | ||||||
|  | 	if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mib = []_C_int{CTL_KERN, KERN_OSRELEASE} | ||||||
|  | 	n = unsafe.Sizeof(uname.Release) | ||||||
|  | 	if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mib = []_C_int{CTL_KERN, KERN_VERSION} | ||||||
|  | 	n = unsafe.Sizeof(uname.Version) | ||||||
|  | 	if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// The version might have newlines or tabs in it, convert them to | ||||||
|  | 	// spaces. | ||||||
|  | 	for i, b := range uname.Version { | ||||||
|  | 		if b == '\n' || b == '\t' { | ||||||
|  | 			if i == len(uname.Version)-1 { | ||||||
|  | 				uname.Version[i] = 0 | ||||||
|  | 			} else { | ||||||
|  | 				uname.Version[i] = ' ' | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mib = []_C_int{CTL_HW, HW_MACHINE} | ||||||
|  | 	n = unsafe.Sizeof(uname.Machine) | ||||||
|  | 	if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Exposed directly |  * Exposed directly | ||||||
|  */ |  */ | ||||||
| //sys	Access(path string, mode uint32) (err error) | //sys	Access(path string, mode uint32) (err error) | ||||||
| //sys	Adjtime(delta *Timeval, olddelta *Timeval) (err error) | //sys	Adjtime(delta *Timeval, olddelta *Timeval) (err error) | ||||||
|  | //sys	CapEnter() (err error) | ||||||
|  | //sys	capRightsGet(version int, fd int, rightsp *CapRights) (err error) = SYS___CAP_RIGHTS_GET | ||||||
|  | //sys	capRightsLimit(fd int, rightsp *CapRights) (err error) | ||||||
| //sys	Chdir(path string) (err error) | //sys	Chdir(path string) (err error) | ||||||
| //sys	Chflags(path string, flags int) (err error) | //sys	Chflags(path string, flags int) (err error) | ||||||
| //sys	Chmod(path string, mode uint32) (err error) | //sys	Chmod(path string, mode uint32) (err error) | ||||||
| @@ -395,16 +472,20 @@ func Llistxattr(link string, dest []byte) (sz int, err error) { | |||||||
| //sys	ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error) | //sys	ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error) | ||||||
| //sys	ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) | //sys	ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error) | ||||||
| //sys	Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_POSIX_FADVISE | //sys	Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_POSIX_FADVISE | ||||||
|  | //sys	Faccessat(dirfd int, path string, mode uint32, flags int) (err error) | ||||||
| //sys	Fchdir(fd int) (err error) | //sys	Fchdir(fd int) (err error) | ||||||
| //sys	Fchflags(fd int, flags int) (err error) | //sys	Fchflags(fd int, flags int) (err error) | ||||||
| //sys	Fchmod(fd int, mode uint32) (err error) | //sys	Fchmod(fd int, mode uint32) (err error) | ||||||
|  | //sys	Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) | ||||||
| //sys	Fchown(fd int, uid int, gid int) (err error) | //sys	Fchown(fd int, uid int, gid int) (err error) | ||||||
|  | //sys	Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) | ||||||
| //sys	Flock(fd int, how int) (err error) | //sys	Flock(fd int, how int) (err error) | ||||||
| //sys	Fpathconf(fd int, name int) (val int, err error) | //sys	Fpathconf(fd int, name int) (val int, err error) | ||||||
| //sys	Fstat(fd int, stat *Stat_t) (err error) | //sys	Fstat(fd int, stat *Stat_t) (err error) | ||||||
| //sys	Fstatfs(fd int, stat *Statfs_t) (err error) | //sys	Fstatfs(fd int, stat *Statfs_t) (err error) | ||||||
| //sys	Fsync(fd int) (err error) | //sys	Fsync(fd int) (err error) | ||||||
| //sys	Ftruncate(fd int, length int64) (err error) | //sys	Ftruncate(fd int, length int64) (err error) | ||||||
|  | //sys	Getdents(fd int, buf []byte) (n int, err error) | ||||||
| //sys	Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) | //sys	Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) | ||||||
| //sys	Getdtablesize() (size int) | //sys	Getdtablesize() (size int) | ||||||
| //sysnb	Getegid() (egid int) | //sysnb	Getegid() (egid int) | ||||||
| @@ -425,24 +506,24 @@ func Llistxattr(link string, dest []byte) (sz int, err error) { | |||||||
| //sys	Kqueue() (fd int, err error) | //sys	Kqueue() (fd int, err error) | ||||||
| //sys	Lchown(path string, uid int, gid int) (err error) | //sys	Lchown(path string, uid int, gid int) (err error) | ||||||
| //sys	Link(path string, link string) (err error) | //sys	Link(path string, link string) (err error) | ||||||
|  | //sys	Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error) | ||||||
| //sys	Listen(s int, backlog int) (err error) | //sys	Listen(s int, backlog int) (err error) | ||||||
| //sys	Lstat(path string, stat *Stat_t) (err error) | //sys	Lstat(path string, stat *Stat_t) (err error) | ||||||
| //sys	Mkdir(path string, mode uint32) (err error) | //sys	Mkdir(path string, mode uint32) (err error) | ||||||
|  | //sys	Mkdirat(dirfd int, path string, mode uint32) (err error) | ||||||
| //sys	Mkfifo(path string, mode uint32) (err error) | //sys	Mkfifo(path string, mode uint32) (err error) | ||||||
| //sys	Mknod(path string, mode uint32, dev int) (err error) | //sys	Mknod(path string, mode uint32, dev int) (err error) | ||||||
| //sys	Mlock(b []byte) (err error) |  | ||||||
| //sys	Mlockall(flags int) (err error) |  | ||||||
| //sys	Mprotect(b []byte, prot int) (err error) |  | ||||||
| //sys	Munlock(b []byte) (err error) |  | ||||||
| //sys	Munlockall() (err error) |  | ||||||
| //sys	Nanosleep(time *Timespec, leftover *Timespec) (err error) | //sys	Nanosleep(time *Timespec, leftover *Timespec) (err error) | ||||||
| //sys	Open(path string, mode int, perm uint32) (fd int, err error) | //sys	Open(path string, mode int, perm uint32) (fd int, err error) | ||||||
|  | //sys	Openat(fdat int, path string, mode int, perm uint32) (fd int, err error) | ||||||
| //sys	Pathconf(path string, name int) (val int, err error) | //sys	Pathconf(path string, name int) (val int, err error) | ||||||
| //sys	Pread(fd int, p []byte, offset int64) (n int, err error) | //sys	Pread(fd int, p []byte, offset int64) (n int, err error) | ||||||
| //sys	Pwrite(fd int, p []byte, offset int64) (n int, err error) | //sys	Pwrite(fd int, p []byte, offset int64) (n int, err error) | ||||||
| //sys	read(fd int, p []byte) (n int, err error) | //sys	read(fd int, p []byte) (n int, err error) | ||||||
| //sys	Readlink(path string, buf []byte) (n int, err error) | //sys	Readlink(path string, buf []byte) (n int, err error) | ||||||
|  | //sys	Readlinkat(dirfd int, path string, buf []byte) (n int, err error) | ||||||
| //sys	Rename(from string, to string) (err error) | //sys	Rename(from string, to string) (err error) | ||||||
|  | //sys	Renameat(fromfd int, from string, tofd int, to string) (err error) | ||||||
| //sys	Revoke(path string) (err error) | //sys	Revoke(path string) (err error) | ||||||
| //sys	Rmdir(path string) (err error) | //sys	Rmdir(path string) (err error) | ||||||
| //sys	Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK | //sys	Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK | ||||||
| @@ -464,11 +545,13 @@ func Llistxattr(link string, dest []byte) (sz int, err error) { | |||||||
| //sys	Stat(path string, stat *Stat_t) (err error) | //sys	Stat(path string, stat *Stat_t) (err error) | ||||||
| //sys	Statfs(path string, stat *Statfs_t) (err error) | //sys	Statfs(path string, stat *Statfs_t) (err error) | ||||||
| //sys	Symlink(path string, link string) (err error) | //sys	Symlink(path string, link string) (err error) | ||||||
|  | //sys	Symlinkat(oldpath string, newdirfd int, newpath string) (err error) | ||||||
| //sys	Sync() (err error) | //sys	Sync() (err error) | ||||||
| //sys	Truncate(path string, length int64) (err error) | //sys	Truncate(path string, length int64) (err error) | ||||||
| //sys	Umask(newmask int) (oldmask int) | //sys	Umask(newmask int) (oldmask int) | ||||||
| //sys	Undelete(path string) (err error) | //sys	Undelete(path string) (err error) | ||||||
| //sys	Unlink(path string) (err error) | //sys	Unlink(path string) (err error) | ||||||
|  | //sys	Unlinkat(dirfd int, path string, flags int) (err error) | ||||||
| //sys	Unmount(path string, flags int) (err error) | //sys	Unmount(path string, flags int) (err error) | ||||||
| //sys	write(fd int, p []byte) (n int, err error) | //sys	write(fd int, p []byte) (n int, err error) | ||||||
| //sys   mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) | //sys   mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) | ||||||
| @@ -476,6 +559,7 @@ func Llistxattr(link string, dest []byte) (sz int, err error) { | |||||||
| //sys	readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ | //sys	readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ | ||||||
| //sys	writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE | //sys	writelen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_WRITE | ||||||
| //sys	accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) | //sys	accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int, err error) | ||||||
|  | //sys	utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Unimplemented |  * Unimplemented | ||||||
| @@ -509,9 +593,6 @@ func Llistxattr(link string, dest []byte) (sz int, err error) { | |||||||
| // Add_profil | // Add_profil | ||||||
| // Kdebug_trace | // Kdebug_trace | ||||||
| // Sigreturn | // Sigreturn | ||||||
| // Mmap |  | ||||||
| // Mlock |  | ||||||
| // Munlock |  | ||||||
| // Atsocket | // Atsocket | ||||||
| // Kqueue_from_portset_np | // Kqueue_from_portset_np | ||||||
| // Kqueue_portset | // Kqueue_portset | ||||||
| @@ -521,7 +602,6 @@ func Llistxattr(link string, dest []byte) (sz int, err error) { | |||||||
| // Searchfs | // Searchfs | ||||||
| // Delete | // Delete | ||||||
| // Copyfile | // Copyfile | ||||||
| // Poll |  | ||||||
| // Watchevent | // Watchevent | ||||||
| // Waitevent | // Waitevent | ||||||
| // Modwatch | // Modwatch | ||||||
| @@ -604,8 +684,6 @@ func Llistxattr(link string, dest []byte) (sz int, err error) { | |||||||
| // Lio_listio | // Lio_listio | ||||||
| // __pthread_cond_wait | // __pthread_cond_wait | ||||||
| // Iopolicysys | // Iopolicysys | ||||||
| // Mlockall |  | ||||||
| // Munlockall |  | ||||||
| // __pthread_kill | // __pthread_kill | ||||||
| // __pthread_sigmask | // __pthread_sigmask | ||||||
| // __sigwait | // __sigwait | ||||||
| @@ -658,7 +736,6 @@ func Llistxattr(link string, dest []byte) (sz int, err error) { | |||||||
| // Sendmsg_nocancel | // Sendmsg_nocancel | ||||||
| // Recvfrom_nocancel | // Recvfrom_nocancel | ||||||
| // Accept_nocancel | // Accept_nocancel | ||||||
| // Msync_nocancel |  | ||||||
| // Fcntl_nocancel | // Fcntl_nocancel | ||||||
| // Select_nocancel | // Select_nocancel | ||||||
| // Fsync_nocancel | // Fsync_nocancel | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,21 +11,12 @@ import ( | |||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func Getpagesize() int { return 4096 } | func setTimespec(sec, nsec int64) Timespec { | ||||||
|  | 	return Timespec{Sec: int32(sec), Nsec: int32(nsec)} | ||||||
| func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } |  | ||||||
|  |  | ||||||
| func NsecToTimespec(nsec int64) (ts Timespec) { |  | ||||||
| 	ts.Sec = int32(nsec / 1e9) |  | ||||||
| 	ts.Nsec = int32(nsec % 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NsecToTimeval(nsec int64) (tv Timeval) { | func setTimeval(sec, usec int64) Timeval { | ||||||
| 	nsec += 999 // round up to microsecond | 	return Timeval{Sec: int32(sec), Usec: int32(usec)} | ||||||
| 	tv.Usec = int32(nsec % 1e9 / 1e3) |  | ||||||
| 	tv.Sec = int32(nsec / 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func SetKevent(k *Kevent_t, fd, mode, flags int) { | func SetKevent(k *Kevent_t, fd, mode, flags int) { | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,21 +11,12 @@ import ( | |||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func Getpagesize() int { return 4096 } | func setTimespec(sec, nsec int64) Timespec { | ||||||
|  | 	return Timespec{Sec: sec, Nsec: nsec} | ||||||
| func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } |  | ||||||
|  |  | ||||||
| func NsecToTimespec(nsec int64) (ts Timespec) { |  | ||||||
| 	ts.Sec = nsec / 1e9 |  | ||||||
| 	ts.Nsec = nsec % 1e9 |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NsecToTimeval(nsec int64) (tv Timeval) { | func setTimeval(sec, usec int64) Timeval { | ||||||
| 	nsec += 999 // round up to microsecond | 	return Timeval{Sec: sec, Usec: usec} | ||||||
| 	tv.Usec = nsec % 1e9 / 1e3 |  | ||||||
| 	tv.Sec = int64(nsec / 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func SetKevent(k *Kevent_t, fd, mode, flags int) { | func SetKevent(k *Kevent_t, fd, mode, flags int) { | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,21 +11,12 @@ import ( | |||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func Getpagesize() int { return 4096 } | func setTimespec(sec, nsec int64) Timespec { | ||||||
|  | 	return Timespec{Sec: sec, Nsec: int32(nsec)} | ||||||
| func TimespecToNsec(ts Timespec) int64 { return ts.Sec*1e9 + int64(ts.Nsec) } |  | ||||||
|  |  | ||||||
| func NsecToTimespec(nsec int64) (ts Timespec) { |  | ||||||
| 	ts.Sec = nsec / 1e9 |  | ||||||
| 	ts.Nsec = int32(nsec % 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NsecToTimeval(nsec int64) (tv Timeval) { | func setTimeval(sec, usec int64) Timeval { | ||||||
| 	nsec += 999 // round up to microsecond | 	return Timeval{Sec: sec, Usec: int32(usec)} | ||||||
| 	tv.Usec = int32(nsec % 1e9 / 1e3) |  | ||||||
| 	tv.Sec = nsec / 1e9 |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func SetKevent(k *Kevent_t, fd, mode, flags int) { | func SetKevent(k *Kevent_t, fd, mode, flags int) { | ||||||
|   | |||||||
							
								
								
									
										267
									
								
								vendor/golang.org/x/sys/unix/syscall_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										267
									
								
								vendor/golang.org/x/sys/unix/syscall_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -36,6 +36,59 @@ func Creat(path string, mode uint32) (fd int, err error) { | |||||||
| 	return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode) | 	return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | //sys	fchmodat(dirfd int, path string, mode uint32) (err error) | ||||||
|  |  | ||||||
|  | func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { | ||||||
|  | 	// Linux fchmodat doesn't support the flags parameter. Mimick glibc's behavior | ||||||
|  | 	// and check the flags. Otherwise the mode would be applied to the symlink | ||||||
|  | 	// destination which is not what the user expects. | ||||||
|  | 	if flags&^AT_SYMLINK_NOFOLLOW != 0 { | ||||||
|  | 		return EINVAL | ||||||
|  | 	} else if flags&AT_SYMLINK_NOFOLLOW != 0 { | ||||||
|  | 		return EOPNOTSUPP | ||||||
|  | 	} | ||||||
|  | 	return fchmodat(dirfd, path, mode) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //sys	ioctl(fd int, req uint, arg uintptr) (err error) | ||||||
|  |  | ||||||
|  | // ioctl itself should not be exposed directly, but additional get/set | ||||||
|  | // functions for specific types are permissible. | ||||||
|  |  | ||||||
|  | // IoctlSetInt performs an ioctl operation which sets an integer value | ||||||
|  | // on fd, using the specified request number. | ||||||
|  | func IoctlSetInt(fd int, req uint, value int) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(value)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlSetWinsize(fd int, req uint, value *Winsize) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(unsafe.Pointer(value))) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlSetTermios(fd int, req uint, value *Termios) error { | ||||||
|  | 	return ioctl(fd, req, uintptr(unsafe.Pointer(value))) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // IoctlGetInt performs an ioctl operation which gets an integer value | ||||||
|  | // from fd, using the specified request number. | ||||||
|  | func IoctlGetInt(fd int, req uint) (int, error) { | ||||||
|  | 	var value int | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return value, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlGetWinsize(fd int, req uint) (*Winsize, error) { | ||||||
|  | 	var value Winsize | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return &value, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func IoctlGetTermios(fd int, req uint) (*Termios, error) { | ||||||
|  | 	var value Termios | ||||||
|  | 	err := ioctl(fd, req, uintptr(unsafe.Pointer(&value))) | ||||||
|  | 	return &value, err | ||||||
|  | } | ||||||
|  |  | ||||||
| //sys	Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) | //sys	Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) | ||||||
|  |  | ||||||
| func Link(oldpath string, newpath string) (err error) { | func Link(oldpath string, newpath string) (err error) { | ||||||
| @@ -299,10 +352,14 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func Mkfifo(path string, mode uint32) (err error) { | func Mkfifo(path string, mode uint32) error { | ||||||
| 	return Mknod(path, mode|S_IFIFO, 0) | 	return Mknod(path, mode|S_IFIFO, 0) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func Mkfifoat(dirfd int, path string, mode uint32) error { | ||||||
|  | 	return Mknodat(dirfd, path, mode|S_IFIFO, 0) | ||||||
|  | } | ||||||
|  |  | ||||||
| func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { | func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { | ||||||
| 	if sa.Port < 0 || sa.Port > 0xFFFF { | 	if sa.Port < 0 || sa.Port > 0xFFFF { | ||||||
| 		return nil, 0, EINVAL | 		return nil, 0, EINVAL | ||||||
| @@ -744,10 +801,124 @@ func GetsockoptUcred(fd, level, opt int) (*Ucred, error) { | |||||||
| 	return &value, err | 	return &value, err | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func GetsockoptTCPInfo(fd, level, opt int) (*TCPInfo, error) { | ||||||
|  | 	var value TCPInfo | ||||||
|  | 	vallen := _Socklen(SizeofTCPInfo) | ||||||
|  | 	err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen) | ||||||
|  | 	return &value, err | ||||||
|  | } | ||||||
|  |  | ||||||
| func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) { | func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) { | ||||||
| 	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) | 	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Keyctl Commands (http://man7.org/linux/man-pages/man2/keyctl.2.html) | ||||||
|  |  | ||||||
|  | // KeyctlInt calls keyctl commands in which each argument is an int. | ||||||
|  | // These commands are KEYCTL_REVOKE, KEYCTL_CHOWN, KEYCTL_CLEAR, KEYCTL_LINK, | ||||||
|  | // KEYCTL_UNLINK, KEYCTL_NEGATE, KEYCTL_SET_REQKEY_KEYRING, KEYCTL_SET_TIMEOUT, | ||||||
|  | // KEYCTL_ASSUME_AUTHORITY, KEYCTL_SESSION_TO_PARENT, KEYCTL_REJECT, | ||||||
|  | // KEYCTL_INVALIDATE, and KEYCTL_GET_PERSISTENT. | ||||||
|  | //sys	KeyctlInt(cmd int, arg2 int, arg3 int, arg4 int, arg5 int) (ret int, err error) = SYS_KEYCTL | ||||||
|  |  | ||||||
|  | // KeyctlBuffer calls keyctl commands in which the third and fourth | ||||||
|  | // arguments are a buffer and its length, respectively. | ||||||
|  | // These commands are KEYCTL_UPDATE, KEYCTL_READ, and KEYCTL_INSTANTIATE. | ||||||
|  | //sys	KeyctlBuffer(cmd int, arg2 int, buf []byte, arg5 int) (ret int, err error) = SYS_KEYCTL | ||||||
|  |  | ||||||
|  | // KeyctlString calls keyctl commands which return a string. | ||||||
|  | // These commands are KEYCTL_DESCRIBE and KEYCTL_GET_SECURITY. | ||||||
|  | func KeyctlString(cmd int, id int) (string, error) { | ||||||
|  | 	// We must loop as the string data may change in between the syscalls. | ||||||
|  | 	// We could allocate a large buffer here to reduce the chance that the | ||||||
|  | 	// syscall needs to be called twice; however, this is unnecessary as | ||||||
|  | 	// the performance loss is negligible. | ||||||
|  | 	var buffer []byte | ||||||
|  | 	for { | ||||||
|  | 		// Try to fill the buffer with data | ||||||
|  | 		length, err := KeyctlBuffer(cmd, id, buffer, 0) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return "", err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Check if the data was written | ||||||
|  | 		if length <= len(buffer) { | ||||||
|  | 			// Exclude the null terminator | ||||||
|  | 			return string(buffer[:length-1]), nil | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Make a bigger buffer if needed | ||||||
|  | 		buffer = make([]byte, length) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Keyctl commands with special signatures. | ||||||
|  |  | ||||||
|  | // KeyctlGetKeyringID implements the KEYCTL_GET_KEYRING_ID command. | ||||||
|  | // See the full documentation at: | ||||||
|  | // http://man7.org/linux/man-pages/man3/keyctl_get_keyring_ID.3.html | ||||||
|  | func KeyctlGetKeyringID(id int, create bool) (ringid int, err error) { | ||||||
|  | 	createInt := 0 | ||||||
|  | 	if create { | ||||||
|  | 		createInt = 1 | ||||||
|  | 	} | ||||||
|  | 	return KeyctlInt(KEYCTL_GET_KEYRING_ID, id, createInt, 0, 0) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // KeyctlSetperm implements the KEYCTL_SETPERM command. The perm value is the | ||||||
|  | // key handle permission mask as described in the "keyctl setperm" section of | ||||||
|  | // http://man7.org/linux/man-pages/man1/keyctl.1.html. | ||||||
|  | // See the full documentation at: | ||||||
|  | // http://man7.org/linux/man-pages/man3/keyctl_setperm.3.html | ||||||
|  | func KeyctlSetperm(id int, perm uint32) error { | ||||||
|  | 	_, err := KeyctlInt(KEYCTL_SETPERM, id, int(perm), 0, 0) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //sys	keyctlJoin(cmd int, arg2 string) (ret int, err error) = SYS_KEYCTL | ||||||
|  |  | ||||||
|  | // KeyctlJoinSessionKeyring implements the KEYCTL_JOIN_SESSION_KEYRING command. | ||||||
|  | // See the full documentation at: | ||||||
|  | // http://man7.org/linux/man-pages/man3/keyctl_join_session_keyring.3.html | ||||||
|  | func KeyctlJoinSessionKeyring(name string) (ringid int, err error) { | ||||||
|  | 	return keyctlJoin(KEYCTL_JOIN_SESSION_KEYRING, name) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //sys	keyctlSearch(cmd int, arg2 int, arg3 string, arg4 string, arg5 int) (ret int, err error) = SYS_KEYCTL | ||||||
|  |  | ||||||
|  | // KeyctlSearch implements the KEYCTL_SEARCH command. | ||||||
|  | // See the full documentation at: | ||||||
|  | // http://man7.org/linux/man-pages/man3/keyctl_search.3.html | ||||||
|  | func KeyctlSearch(ringid int, keyType, description string, destRingid int) (id int, err error) { | ||||||
|  | 	return keyctlSearch(KEYCTL_SEARCH, ringid, keyType, description, destRingid) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //sys	keyctlIOV(cmd int, arg2 int, payload []Iovec, arg5 int) (err error) = SYS_KEYCTL | ||||||
|  |  | ||||||
|  | // KeyctlInstantiateIOV implements the KEYCTL_INSTANTIATE_IOV command. This | ||||||
|  | // command is similar to KEYCTL_INSTANTIATE, except that the payload is a slice | ||||||
|  | // of Iovec (each of which represents a buffer) instead of a single buffer. | ||||||
|  | // See the full documentation at: | ||||||
|  | // http://man7.org/linux/man-pages/man3/keyctl_instantiate_iov.3.html | ||||||
|  | func KeyctlInstantiateIOV(id int, payload []Iovec, ringid int) error { | ||||||
|  | 	return keyctlIOV(KEYCTL_INSTANTIATE_IOV, id, payload, ringid) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //sys	keyctlDH(cmd int, arg2 *KeyctlDHParams, buf []byte) (ret int, err error) = SYS_KEYCTL | ||||||
|  |  | ||||||
|  | // KeyctlDHCompute implements the KEYCTL_DH_COMPUTE command. This command | ||||||
|  | // computes a Diffie-Hellman shared secret based on the provide params. The | ||||||
|  | // secret is written to the provided buffer and the returned size is the number | ||||||
|  | // of bytes written (returning an error if there is insufficient space in the | ||||||
|  | // buffer). If a nil buffer is passed in, this function returns the minimum | ||||||
|  | // buffer length needed to store the appropriate data. Note that this differs | ||||||
|  | // from KEYCTL_READ's behavior which always returns the requested payload size. | ||||||
|  | // See the full documentation at: | ||||||
|  | // http://man7.org/linux/man-pages/man3/keyctl_dh_compute.3.html | ||||||
|  | func KeyctlDHCompute(params *KeyctlDHParams, buffer []byte) (size int, err error) { | ||||||
|  | 	return keyctlDH(KEYCTL_DH_COMPUTE, params, buffer) | ||||||
|  | } | ||||||
|  |  | ||||||
| func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) { | func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) { | ||||||
| 	var msg Msghdr | 	var msg Msghdr | ||||||
| 	var rsa RawSockaddrAny | 	var rsa RawSockaddrAny | ||||||
| @@ -755,17 +926,22 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from | |||||||
| 	msg.Namelen = uint32(SizeofSockaddrAny) | 	msg.Namelen = uint32(SizeofSockaddrAny) | ||||||
| 	var iov Iovec | 	var iov Iovec | ||||||
| 	if len(p) > 0 { | 	if len(p) > 0 { | ||||||
| 		iov.Base = (*byte)(unsafe.Pointer(&p[0])) | 		iov.Base = &p[0] | ||||||
| 		iov.SetLen(len(p)) | 		iov.SetLen(len(p)) | ||||||
| 	} | 	} | ||||||
| 	var dummy byte | 	var dummy byte | ||||||
| 	if len(oob) > 0 { | 	if len(oob) > 0 { | ||||||
|  | 		var sockType int | ||||||
|  | 		sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
| 		// receive at least one normal byte | 		// receive at least one normal byte | ||||||
| 		if len(p) == 0 { | 		if sockType != SOCK_DGRAM && len(p) == 0 { | ||||||
| 			iov.Base = &dummy | 			iov.Base = &dummy | ||||||
| 			iov.SetLen(1) | 			iov.SetLen(1) | ||||||
| 		} | 		} | ||||||
| 		msg.Control = (*byte)(unsafe.Pointer(&oob[0])) | 		msg.Control = &oob[0] | ||||||
| 		msg.SetControllen(len(oob)) | 		msg.SetControllen(len(oob)) | ||||||
| 	} | 	} | ||||||
| 	msg.Iov = &iov | 	msg.Iov = &iov | ||||||
| @@ -798,21 +974,26 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	var msg Msghdr | 	var msg Msghdr | ||||||
| 	msg.Name = (*byte)(unsafe.Pointer(ptr)) | 	msg.Name = (*byte)(ptr) | ||||||
| 	msg.Namelen = uint32(salen) | 	msg.Namelen = uint32(salen) | ||||||
| 	var iov Iovec | 	var iov Iovec | ||||||
| 	if len(p) > 0 { | 	if len(p) > 0 { | ||||||
| 		iov.Base = (*byte)(unsafe.Pointer(&p[0])) | 		iov.Base = &p[0] | ||||||
| 		iov.SetLen(len(p)) | 		iov.SetLen(len(p)) | ||||||
| 	} | 	} | ||||||
| 	var dummy byte | 	var dummy byte | ||||||
| 	if len(oob) > 0 { | 	if len(oob) > 0 { | ||||||
|  | 		var sockType int | ||||||
|  | 		sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return 0, err | ||||||
|  | 		} | ||||||
| 		// send at least one normal byte | 		// send at least one normal byte | ||||||
| 		if len(p) == 0 { | 		if sockType != SOCK_DGRAM && len(p) == 0 { | ||||||
| 			iov.Base = &dummy | 			iov.Base = &dummy | ||||||
| 			iov.SetLen(1) | 			iov.SetLen(1) | ||||||
| 		} | 		} | ||||||
| 		msg.Control = (*byte)(unsafe.Pointer(&oob[0])) | 		msg.Control = &oob[0] | ||||||
| 		msg.SetControllen(len(oob)) | 		msg.SetControllen(len(oob)) | ||||||
| 	} | 	} | ||||||
| 	msg.Iov = &iov | 	msg.Iov = &iov | ||||||
| @@ -944,6 +1125,10 @@ func PtracePokeData(pid int, addr uintptr, data []byte) (count int, err error) { | |||||||
| 	return ptracePoke(PTRACE_POKEDATA, PTRACE_PEEKDATA, pid, addr, data) | 	return ptracePoke(PTRACE_POKEDATA, PTRACE_PEEKDATA, pid, addr, data) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func PtracePokeUser(pid int, addr uintptr, data []byte) (count int, err error) { | ||||||
|  | 	return ptracePoke(PTRACE_POKEUSR, PTRACE_PEEKUSR, pid, addr, data) | ||||||
|  | } | ||||||
|  |  | ||||||
| func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) { | func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) { | ||||||
| 	return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout))) | 	return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout))) | ||||||
| } | } | ||||||
| @@ -983,38 +1168,24 @@ func Reboot(cmd int) (err error) { | |||||||
| 	return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "") | 	return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "") | ||||||
| } | } | ||||||
|  |  | ||||||
| func clen(n []byte) int { |  | ||||||
| 	for i := 0; i < len(n); i++ { |  | ||||||
| 		if n[i] == 0 { |  | ||||||
| 			return i |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return len(n) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func ReadDirent(fd int, buf []byte) (n int, err error) { | func ReadDirent(fd int, buf []byte) (n int, err error) { | ||||||
| 	return Getdents(fd, buf) | 	return Getdents(fd, buf) | ||||||
| } | } | ||||||
|  |  | ||||||
| func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) { | func direntIno(buf []byte) (uint64, bool) { | ||||||
| 	origlen := len(buf) | 	return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) | ||||||
| 	count = 0 | } | ||||||
| 	for max != 0 && len(buf) > 0 { |  | ||||||
| 		dirent := (*Dirent)(unsafe.Pointer(&buf[0])) | func direntReclen(buf []byte) (uint64, bool) { | ||||||
| 		buf = buf[dirent.Reclen:] | 	return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen)) | ||||||
| 		if dirent.Ino == 0 { // File absent in directory. | } | ||||||
| 			continue |  | ||||||
|  | func direntNamlen(buf []byte) (uint64, bool) { | ||||||
|  | 	reclen, ok := direntReclen(buf) | ||||||
|  | 	if !ok { | ||||||
|  | 		return 0, false | ||||||
| 	} | 	} | ||||||
| 		bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0])) | 	return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true | ||||||
| 		var name = string(bytes[0:clen(bytes[:])]) |  | ||||||
| 		if name == "." || name == ".." { // Useless names |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		max-- |  | ||||||
| 		count++ |  | ||||||
| 		names = append(names, name) |  | ||||||
| 	} |  | ||||||
| 	return origlen - len(buf), count, names |  | ||||||
| } | } | ||||||
|  |  | ||||||
| //sys	mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) | //sys	mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) | ||||||
| @@ -1040,22 +1211,24 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri | |||||||
|  * Direct access |  * Direct access | ||||||
|  */ |  */ | ||||||
| //sys	Acct(path string) (err error) | //sys	Acct(path string) (err error) | ||||||
|  | //sys	AddKey(keyType string, description string, payload []byte, ringid int) (id int, err error) | ||||||
| //sys	Adjtimex(buf *Timex) (state int, err error) | //sys	Adjtimex(buf *Timex) (state int, err error) | ||||||
| //sys	Chdir(path string) (err error) | //sys	Chdir(path string) (err error) | ||||||
| //sys	Chroot(path string) (err error) | //sys	Chroot(path string) (err error) | ||||||
| //sys	ClockGettime(clockid int32, time *Timespec) (err error) | //sys	ClockGettime(clockid int32, time *Timespec) (err error) | ||||||
| //sys	Close(fd int) (err error) | //sys	Close(fd int) (err error) | ||||||
|  | //sys	CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) | ||||||
| //sys	Dup(oldfd int) (fd int, err error) | //sys	Dup(oldfd int) (fd int, err error) | ||||||
| //sys	Dup3(oldfd int, newfd int, flags int) (err error) | //sys	Dup3(oldfd int, newfd int, flags int) (err error) | ||||||
| //sysnb	EpollCreate(size int) (fd int, err error) | //sysnb	EpollCreate(size int) (fd int, err error) | ||||||
| //sysnb	EpollCreate1(flag int) (fd int, err error) | //sysnb	EpollCreate1(flag int) (fd int, err error) | ||||||
| //sysnb	EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) | //sysnb	EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) | ||||||
|  | //sys	Eventfd(initval uint, flags int) (fd int, err error) = SYS_EVENTFD2 | ||||||
| //sys	Exit(code int) = SYS_EXIT_GROUP | //sys	Exit(code int) = SYS_EXIT_GROUP | ||||||
| //sys	Faccessat(dirfd int, path string, mode uint32, flags int) (err error) | //sys	Faccessat(dirfd int, path string, mode uint32, flags int) (err error) | ||||||
| //sys	Fallocate(fd int, mode uint32, off int64, len int64) (err error) | //sys	Fallocate(fd int, mode uint32, off int64, len int64) (err error) | ||||||
| //sys	Fchdir(fd int) (err error) | //sys	Fchdir(fd int) (err error) | ||||||
| //sys	Fchmod(fd int, mode uint32) (err error) | //sys	Fchmod(fd int, mode uint32) (err error) | ||||||
| //sys	Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) |  | ||||||
| //sys	Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) | //sys	Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) | ||||||
| //sys	fcntl(fd int, cmd int, arg int) (val int, err error) | //sys	fcntl(fd int, cmd int, arg int) (val int, err error) | ||||||
| //sys	Fdatasync(fd int) (err error) | //sys	Fdatasync(fd int) (err error) | ||||||
| @@ -1082,16 +1255,22 @@ func Getpgrp() (pid int) { | |||||||
| //sysnb	InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) | //sysnb	InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) | ||||||
| //sysnb	Kill(pid int, sig syscall.Signal) (err error) | //sysnb	Kill(pid int, sig syscall.Signal) (err error) | ||||||
| //sys	Klogctl(typ int, buf []byte) (n int, err error) = SYS_SYSLOG | //sys	Klogctl(typ int, buf []byte) (n int, err error) = SYS_SYSLOG | ||||||
|  | //sys	Lgetxattr(path string, attr string, dest []byte) (sz int, err error) | ||||||
| //sys	Listxattr(path string, dest []byte) (sz int, err error) | //sys	Listxattr(path string, dest []byte) (sz int, err error) | ||||||
|  | //sys	Llistxattr(path string, dest []byte) (sz int, err error) | ||||||
|  | //sys	Lremovexattr(path string, attr string) (err error) | ||||||
|  | //sys	Lsetxattr(path string, attr string, data []byte, flags int) (err error) | ||||||
| //sys	Mkdirat(dirfd int, path string, mode uint32) (err error) | //sys	Mkdirat(dirfd int, path string, mode uint32) (err error) | ||||||
| //sys	Mknodat(dirfd int, path string, mode uint32, dev int) (err error) | //sys	Mknodat(dirfd int, path string, mode uint32, dev int) (err error) | ||||||
| //sys	Nanosleep(time *Timespec, leftover *Timespec) (err error) | //sys	Nanosleep(time *Timespec, leftover *Timespec) (err error) | ||||||
| //sys	PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT | //sys	PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT | ||||||
| //sysnb prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64 | //sysnb prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64 | ||||||
| //sys   Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error) | //sys   Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error) | ||||||
|  | //sys	Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) = SYS_PSELECT6 | ||||||
| //sys	read(fd int, p []byte) (n int, err error) | //sys	read(fd int, p []byte) (n int, err error) | ||||||
| //sys	Removexattr(path string, attr string) (err error) | //sys	Removexattr(path string, attr string) (err error) | ||||||
| //sys	Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) | //sys	Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) | ||||||
|  | //sys	RequestKey(keyType string, description string, callback string, destRingid int) (id int, err error) | ||||||
| //sys	Setdomainname(p []byte) (err error) | //sys	Setdomainname(p []byte) (err error) | ||||||
| //sys	Sethostname(p []byte) (err error) | //sys	Sethostname(p []byte) (err error) | ||||||
| //sysnb	Setpgid(pid int, pgid int) (err error) | //sysnb	Setpgid(pid int, pgid int) (err error) | ||||||
| @@ -1115,6 +1294,7 @@ func Setgid(uid int) (err error) { | |||||||
| //sys	Setpriority(which int, who int, prio int) (err error) | //sys	Setpriority(which int, who int, prio int) (err error) | ||||||
| //sys	Setxattr(path string, attr string, data []byte, flags int) (err error) | //sys	Setxattr(path string, attr string, data []byte, flags int) (err error) | ||||||
| //sys	Sync() | //sys	Sync() | ||||||
|  | //sys	Syncfs(fd int) (err error) | ||||||
| //sysnb	Sysinfo(info *Sysinfo_t) (err error) | //sysnb	Sysinfo(info *Sysinfo_t) (err error) | ||||||
| //sys	Tee(rfd int, wfd int, len int, flags int) (n int64, err error) | //sys	Tee(rfd int, wfd int, len int, flags int) (n int64, err error) | ||||||
| //sysnb	Tgkill(tgid int, tid int, sig syscall.Signal) (err error) | //sysnb	Tgkill(tgid int, tid int, sig syscall.Signal) (err error) | ||||||
| @@ -1149,8 +1329,9 @@ func Munmap(b []byte) (err error) { | |||||||
| //sys	Madvise(b []byte, advice int) (err error) | //sys	Madvise(b []byte, advice int) (err error) | ||||||
| //sys	Mprotect(b []byte, prot int) (err error) | //sys	Mprotect(b []byte, prot int) (err error) | ||||||
| //sys	Mlock(b []byte) (err error) | //sys	Mlock(b []byte) (err error) | ||||||
| //sys	Munlock(b []byte) (err error) |  | ||||||
| //sys	Mlockall(flags int) (err error) | //sys	Mlockall(flags int) (err error) | ||||||
|  | //sys	Msync(b []byte, flags int) (err error) | ||||||
|  | //sys	Munlock(b []byte) (err error) | ||||||
| //sys	Munlockall() (err error) | //sys	Munlockall() (err error) | ||||||
|  |  | ||||||
| // Vmsplice splices user pages from a slice of Iovecs into a pipe specified by fd, | // Vmsplice splices user pages from a slice of Iovecs into a pipe specified by fd, | ||||||
| @@ -1175,7 +1356,6 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { | |||||||
| /* | /* | ||||||
|  * Unimplemented |  * Unimplemented | ||||||
|  */ |  */ | ||||||
| // AddKey |  | ||||||
| // AfsSyscall | // AfsSyscall | ||||||
| // Alarm | // Alarm | ||||||
| // ArchPrctl | // ArchPrctl | ||||||
| @@ -1191,7 +1371,6 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { | |||||||
| // EpollCtlOld | // EpollCtlOld | ||||||
| // EpollPwait | // EpollPwait | ||||||
| // EpollWaitOld | // EpollWaitOld | ||||||
| // Eventfd |  | ||||||
| // Execve | // Execve | ||||||
| // Fgetxattr | // Fgetxattr | ||||||
| // Flistxattr | // Flistxattr | ||||||
| @@ -1210,23 +1389,16 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { | |||||||
| // IoGetevents | // IoGetevents | ||||||
| // IoSetup | // IoSetup | ||||||
| // IoSubmit | // IoSubmit | ||||||
| // Ioctl |  | ||||||
| // IoprioGet | // IoprioGet | ||||||
| // IoprioSet | // IoprioSet | ||||||
| // KexecLoad | // KexecLoad | ||||||
| // Keyctl |  | ||||||
| // Lgetxattr |  | ||||||
| // Llistxattr |  | ||||||
| // LookupDcookie | // LookupDcookie | ||||||
| // Lremovexattr |  | ||||||
| // Lsetxattr |  | ||||||
| // Mbind | // Mbind | ||||||
| // MigratePages | // MigratePages | ||||||
| // Mincore | // Mincore | ||||||
| // ModifyLdt | // ModifyLdt | ||||||
| // Mount | // Mount | ||||||
| // MovePages | // MovePages | ||||||
| // Mprotect |  | ||||||
| // MqGetsetattr | // MqGetsetattr | ||||||
| // MqNotify | // MqNotify | ||||||
| // MqOpen | // MqOpen | ||||||
| @@ -1238,8 +1410,6 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { | |||||||
| // Msgget | // Msgget | ||||||
| // Msgrcv | // Msgrcv | ||||||
| // Msgsnd | // Msgsnd | ||||||
| // Msync |  | ||||||
| // Newfstatat |  | ||||||
| // Nfsservctl | // Nfsservctl | ||||||
| // Personality | // Personality | ||||||
| // Pselect6 | // Pselect6 | ||||||
| @@ -1250,7 +1420,6 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) { | |||||||
| // Readahead | // Readahead | ||||||
| // Readv | // Readv | ||||||
| // RemapFilePages | // RemapFilePages | ||||||
| // RequestKey |  | ||||||
| // RestartSyscall | // RestartSyscall | ||||||
| // RtSigaction | // RtSigaction | ||||||
| // RtSigpending | // RtSigpending | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								vendor/golang.org/x/sys/unix/syscall_linux_386.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/golang.org/x/sys/unix/syscall_linux_386.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -14,21 +14,12 @@ import ( | |||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func Getpagesize() int { return 4096 } | func setTimespec(sec, nsec int64) Timespec { | ||||||
|  | 	return Timespec{Sec: int32(sec), Nsec: int32(nsec)} | ||||||
| func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) } |  | ||||||
|  |  | ||||||
| func NsecToTimespec(nsec int64) (ts Timespec) { |  | ||||||
| 	ts.Sec = int32(nsec / 1e9) |  | ||||||
| 	ts.Nsec = int32(nsec % 1e9) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func NsecToTimeval(nsec int64) (tv Timeval) { | func setTimeval(sec, usec int64) Timeval { | ||||||
| 	nsec += 999 // round up to microsecond | 	return Timeval{Sec: int32(sec), Usec: int32(usec)} | ||||||
| 	tv.Sec = int32(nsec / 1e9) |  | ||||||
| 	tv.Usec = int32(nsec % 1e9 / 1e3) |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| //sysnb	pipe(p *[2]_C_int) (err error) | //sysnb	pipe(p *[2]_C_int) (err error) | ||||||
| @@ -63,6 +54,7 @@ func Pipe2(p []int, flags int) (err error) { | |||||||
| //sys	Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64 | //sys	Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64 | ||||||
| //sys	Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32 | //sys	Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32 | ||||||
| //sys	Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 | //sys	Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 | ||||||
|  | //sys	Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 | ||||||
| //sys	Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64 | //sys	Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64 | ||||||
| //sysnb	Getegid() (egid int) = SYS_GETEGID32 | //sysnb	Getegid() (egid int) = SYS_GETEGID32 | ||||||
| //sysnb	Geteuid() (euid int) = SYS_GETEUID32 | //sysnb	Geteuid() (euid int) = SYS_GETEUID32 | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 Wim
					Wim