github.com/devops-filetransfer/sshego@v7.0.4+incompatible/_vendor/golang.org/x/crypto/ssh/server.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ssh
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"net"
    13  	"strings"
    14  )
    15  
    16  // The Permissions type holds fine-grained permissions that are
    17  // specific to a user or a specific authentication method for a
    18  // user. Permissions, except for "source-address", must be enforced in
    19  // the server application layer, after successful authentication. The
    20  // Permissions are passed on in ServerConn so a server implementation
    21  // can honor them.
    22  type Permissions struct {
    23  	// Critical options restrict default permissions. Common
    24  	// restrictions are "source-address" and "force-command". If
    25  	// the server cannot enforce the restriction, or does not
    26  	// recognize it, the user should not authenticate.
    27  	CriticalOptions map[string]string
    28  
    29  	// Extensions are extra functionality that the server may
    30  	// offer on authenticated connections. Common extensions are
    31  	// "permit-agent-forwarding", "permit-X11-forwarding". Lack of
    32  	// support for an extension does not preclude authenticating a
    33  	// user.
    34  	Extensions map[string]string
    35  }
    36  
    37  // ServerConfig holds server specific configuration data.
    38  type ServerConfig struct {
    39  	// Config contains configuration shared between client and server.
    40  	Config
    41  
    42  	hostKeys []Signer
    43  
    44  	// NoClientAuth is true if clients are allowed to connect without
    45  	// authenticating.
    46  	NoClientAuth bool
    47  
    48  	// MaxAuthTries specifies the maximum number of authentication attempts
    49  	// permitted per connection. If set to a negative number, the number of
    50  	// attempts are unlimited. If set to zero, the number of attempts are limited
    51  	// to 6.
    52  	MaxAuthTries int
    53  
    54  	// PasswordCallback, if non-nil, is called when a user
    55  	// attempts to authenticate using a password.
    56  	PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
    57  
    58  	// PublicKeyCallback, if non-nil, is called when a client attempts public
    59  	// key authentication. It must return true if the given public key is
    60  	// valid for the given user. For example, see CertChecker.Authenticate.
    61  	PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
    62  
    63  	// KeyboardInteractiveCallback, if non-nil, is called when
    64  	// keyboard-interactive authentication is selected (RFC
    65  	// 4256). The client object's Challenge function should be
    66  	// used to query the user. The callback may offer multiple
    67  	// Challenge rounds. To avoid information leaks, the client
    68  	// should be presented a challenge even if the user is
    69  	// unknown.
    70  	KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
    71  
    72  	// AuthLogCallback, if non-nil, is called to log all authentication
    73  	// attempts.
    74  	AuthLogCallback func(conn ConnMetadata, method string, err error)
    75  
    76  	// ServerVersion is the version identification string to announce in
    77  	// the public handshake.
    78  	// If empty, a reasonable default is used.
    79  	// Note that RFC 4253 section 4.2 requires that this string start with
    80  	// "SSH-2.0-".
    81  	ServerVersion string
    82  }
    83  
    84  // AddHostKey adds a private key as a host key. If an existing host
    85  // key exists with the same algorithm, it is overwritten. Each server
    86  // config must have at least one host key.
    87  func (s *ServerConfig) AddHostKey(key Signer) {
    88  	for i, k := range s.hostKeys {
    89  		if k.PublicKey().Type() == key.PublicKey().Type() {
    90  			s.hostKeys[i] = key
    91  			return
    92  		}
    93  	}
    94  
    95  	s.hostKeys = append(s.hostKeys, key)
    96  }
    97  
    98  // cachedPubKey contains the results of querying whether a public key is
    99  // acceptable for a user.
   100  type cachedPubKey struct {
   101  	user       string
   102  	pubKeyData []byte
   103  	result     error
   104  	perms      *Permissions
   105  }
   106  
   107  const maxCachedPubKeys = 16
   108  
   109  // pubKeyCache caches tests for public keys.  Since SSH clients
   110  // will query whether a public key is acceptable before attempting to
   111  // authenticate with it, we end up with duplicate queries for public
   112  // key validity.  The cache only applies to a single ServerConn.
   113  type pubKeyCache struct {
   114  	keys []cachedPubKey
   115  }
   116  
   117  // get returns the result for a given user/algo/key tuple.
   118  func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
   119  	for _, k := range c.keys {
   120  		if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) {
   121  			return k, true
   122  		}
   123  	}
   124  	return cachedPubKey{}, false
   125  }
   126  
   127  // add adds the given tuple to the cache.
   128  func (c *pubKeyCache) add(candidate cachedPubKey) {
   129  	if len(c.keys) < maxCachedPubKeys {
   130  		c.keys = append(c.keys, candidate)
   131  	}
   132  }
   133  
   134  // ServerConn is an authenticated SSH connection, as seen from the
   135  // server
   136  type ServerConn struct {
   137  	Conn
   138  
   139  	// If the succeeding authentication callback returned a
   140  	// non-nil Permissions pointer, it is stored here.
   141  	Permissions *Permissions
   142  }
   143  
   144  // NewServerConn starts a new SSH server with c as the underlying
   145  // transport.  It starts with a handshake and, if the handshake is
   146  // unsuccessful, it closes the connection and returns an error.  The
   147  // Request and NewChannel channels must be serviced, or the connection
   148  // will hang.
   149  func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
   150  	if config.MaxAuthTries == 0 {
   151  		config.MaxAuthTries = 6
   152  	}
   153  
   154  	fullConf := *config
   155  	fullConf.SetDefaults()
   156  	s := &connection{
   157  		sshConn: sshConn{conn: c},
   158  	}
   159  	perms, err := s.serverHandshake(&fullConf)
   160  	if err != nil {
   161  		c.Close()
   162  		return nil, nil, nil, err
   163  	}
   164  	return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil
   165  }
   166  
   167  // signAndMarshal signs the data with the appropriate algorithm,
   168  // and serializes the result in SSH wire format.
   169  func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) {
   170  	sig, err := k.Sign(rand, data)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  
   175  	return Marshal(sig), nil
   176  }
   177  
   178  // handshake performs key exchange and user authentication.
   179  func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) {
   180  	if len(config.hostKeys) == 0 {
   181  		return nil, errors.New("ssh: server has no host keys")
   182  	}
   183  
   184  	if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil {
   185  		return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
   186  	}
   187  
   188  	if config.ServerVersion != "" {
   189  		s.serverVersion = []byte(config.ServerVersion)
   190  	} else {
   191  		s.serverVersion = []byte(packageVersion)
   192  	}
   193  	var err error
   194  	s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
   195  	if err != nil {
   196  		return nil, err
   197  	}
   198  
   199  	tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */)
   200  	s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
   201  
   202  	if err := s.transport.waitSession(); err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	// We just did the key change, so the session ID is established.
   207  	s.sessionID = s.transport.getSessionID()
   208  
   209  	var packet []byte
   210  	if packet, err = s.transport.readPacket(); err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	var serviceRequest serviceRequestMsg
   215  	if err = Unmarshal(packet, &serviceRequest); err != nil {
   216  		return nil, err
   217  	}
   218  	if serviceRequest.Service != serviceUserAuth {
   219  		return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
   220  	}
   221  	serviceAccept := serviceAcceptMsg{
   222  		Service: serviceUserAuth,
   223  	}
   224  	if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
   225  		return nil, err
   226  	}
   227  
   228  	perms, err := s.serverAuthenticate(config)
   229  	if err != nil {
   230  		return nil, err
   231  	}
   232  	s.mux = newMux(s.transport)
   233  	return perms, err
   234  }
   235  
   236  func isAcceptableAlgo(algo string) bool {
   237  	switch algo {
   238  	case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoED25519,
   239  		CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01:
   240  		return true
   241  	}
   242  	return false
   243  }
   244  
   245  func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
   246  	if addr == nil {
   247  		return errors.New("ssh: no address known for client, but source-address match required")
   248  	}
   249  
   250  	tcpAddr, ok := addr.(*net.TCPAddr)
   251  	if !ok {
   252  		return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
   253  	}
   254  
   255  	for _, sourceAddr := range strings.Split(sourceAddrs, ",") {
   256  		if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
   257  			if allowedIP.Equal(tcpAddr.IP) {
   258  				return nil
   259  			}
   260  		} else {
   261  			_, ipNet, err := net.ParseCIDR(sourceAddr)
   262  			if err != nil {
   263  				return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
   264  			}
   265  
   266  			if ipNet.Contains(tcpAddr.IP) {
   267  				return nil
   268  			}
   269  		}
   270  	}
   271  
   272  	return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
   273  }
   274  
   275  func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
   276  	sessionID := s.transport.getSessionID()
   277  	var cache pubKeyCache
   278  	var perms *Permissions
   279  
   280  	authFailures := 0
   281  
   282  userAuthLoop:
   283  	for {
   284  		if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
   285  			discMsg := &disconnectMsg{
   286  				Reason:  2,
   287  				Message: "too many authentication failures",
   288  			}
   289  
   290  			if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
   291  				return nil, err
   292  			}
   293  
   294  			return nil, discMsg
   295  		}
   296  
   297  		var userAuthReq userAuthRequestMsg
   298  		if packet, err := s.transport.readPacket(); err != nil {
   299  			return nil, err
   300  		} else if err = Unmarshal(packet, &userAuthReq); err != nil {
   301  			return nil, err
   302  		}
   303  
   304  		if userAuthReq.Service != serviceSSH {
   305  			return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
   306  		}
   307  
   308  		s.user = userAuthReq.User
   309  		perms = nil
   310  		authErr := errors.New("no auth passed yet")
   311  
   312  		switch userAuthReq.Method {
   313  		case "none":
   314  			if config.NoClientAuth {
   315  				authErr = nil
   316  			}
   317  
   318  			// allow initial attempt of 'none' without penalty
   319  			if authFailures == 0 {
   320  				authFailures--
   321  			}
   322  		case "password":
   323  			if config.PasswordCallback == nil {
   324  				authErr = errors.New("ssh: password auth not configured")
   325  				break
   326  			}
   327  			payload := userAuthReq.Payload
   328  			if len(payload) < 1 || payload[0] != 0 {
   329  				return nil, parseError(msgUserAuthRequest)
   330  			}
   331  			payload = payload[1:]
   332  			password, payload, ok := parseString(payload)
   333  			if !ok || len(payload) > 0 {
   334  				return nil, parseError(msgUserAuthRequest)
   335  			}
   336  
   337  			perms, authErr = config.PasswordCallback(s, password)
   338  		case "keyboard-interactive":
   339  			if config.KeyboardInteractiveCallback == nil {
   340  				authErr = errors.New("ssh: keyboard-interactive auth not configubred")
   341  				break
   342  			}
   343  
   344  			prompter := &sshClientKeyboardInteractive{s}
   345  			perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge)
   346  		case "publickey":
   347  			if config.PublicKeyCallback == nil {
   348  				authErr = errors.New("ssh: publickey auth not configured")
   349  				break
   350  			}
   351  			payload := userAuthReq.Payload
   352  			if len(payload) < 1 {
   353  				return nil, parseError(msgUserAuthRequest)
   354  			}
   355  			isQuery := payload[0] == 0
   356  			payload = payload[1:]
   357  			algoBytes, payload, ok := parseString(payload)
   358  			if !ok {
   359  				return nil, parseError(msgUserAuthRequest)
   360  			}
   361  			algo := string(algoBytes)
   362  			if !isAcceptableAlgo(algo) {
   363  				authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
   364  				break
   365  			}
   366  
   367  			pubKeyData, payload, ok := parseString(payload)
   368  			if !ok {
   369  				return nil, parseError(msgUserAuthRequest)
   370  			}
   371  
   372  			pubKey, err := ParsePublicKey(pubKeyData)
   373  			if err != nil {
   374  				return nil, err
   375  			}
   376  
   377  			candidate, ok := cache.get(s.user, pubKeyData)
   378  			if !ok {
   379  				candidate.user = s.user
   380  				candidate.pubKeyData = pubKeyData
   381  				candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey)
   382  				if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
   383  					candidate.result = checkSourceAddress(
   384  						s.RemoteAddr(),
   385  						candidate.perms.CriticalOptions[sourceAddressCriticalOption])
   386  				}
   387  				cache.add(candidate)
   388  			}
   389  
   390  			if isQuery {
   391  				// The client can query if the given public key
   392  				// would be okay.
   393  
   394  				if len(payload) > 0 {
   395  					return nil, parseError(msgUserAuthRequest)
   396  				}
   397  
   398  				if candidate.result == nil {
   399  					okMsg := userAuthPubKeyOkMsg{
   400  						Algo:   algo,
   401  						PubKey: pubKeyData,
   402  					}
   403  					if err = s.transport.writePacket(Marshal(&okMsg)); err != nil {
   404  						return nil, err
   405  					}
   406  					continue userAuthLoop
   407  				}
   408  				authErr = candidate.result
   409  			} else {
   410  				sig, payload, ok := parseSignature(payload)
   411  				if !ok || len(payload) > 0 {
   412  					return nil, parseError(msgUserAuthRequest)
   413  				}
   414  				// Ensure the public key algo and signature algo
   415  				// are supported.  Compare the private key
   416  				// algorithm name that corresponds to algo with
   417  				// sig.Format.  This is usually the same, but
   418  				// for certs, the names differ.
   419  				if !isAcceptableAlgo(sig.Format) {
   420  					break
   421  				}
   422  				signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData)
   423  
   424  				if err := pubKey.Verify(signedData, sig); err != nil {
   425  					return nil, err
   426  				}
   427  
   428  				authErr = candidate.result
   429  				perms = candidate.perms
   430  			}
   431  		default:
   432  			authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
   433  		}
   434  
   435  		if config.AuthLogCallback != nil {
   436  			config.AuthLogCallback(s, userAuthReq.Method, authErr)
   437  		}
   438  
   439  		if authErr == nil {
   440  			break userAuthLoop
   441  		}
   442  
   443  		authFailures++
   444  
   445  		var failureMsg userAuthFailureMsg
   446  		if config.PasswordCallback != nil {
   447  			failureMsg.Methods = append(failureMsg.Methods, "password")
   448  		}
   449  		if config.PublicKeyCallback != nil {
   450  			failureMsg.Methods = append(failureMsg.Methods, "publickey")
   451  		}
   452  		if config.KeyboardInteractiveCallback != nil {
   453  			failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
   454  		}
   455  
   456  		if len(failureMsg.Methods) == 0 {
   457  			return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
   458  		}
   459  
   460  		if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil {
   461  			return nil, err
   462  		}
   463  	}
   464  
   465  	if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil {
   466  		return nil, err
   467  	}
   468  	return perms, nil
   469  }
   470  
   471  // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
   472  // asking the client on the other side of a ServerConn.
   473  type sshClientKeyboardInteractive struct {
   474  	*connection
   475  }
   476  
   477  func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
   478  	if len(questions) != len(echos) {
   479  		return nil, errors.New("ssh: echos and questions must have equal length")
   480  	}
   481  
   482  	var prompts []byte
   483  	for i := range questions {
   484  		prompts = appendString(prompts, questions[i])
   485  		prompts = appendBool(prompts, echos[i])
   486  	}
   487  
   488  	if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
   489  		Instruction: instruction,
   490  		NumPrompts:  uint32(len(questions)),
   491  		Prompts:     prompts,
   492  	})); err != nil {
   493  		return nil, err
   494  	}
   495  
   496  	packet, err := c.transport.readPacket()
   497  	if err != nil {
   498  		return nil, err
   499  	}
   500  	if packet[0] != msgUserAuthInfoResponse {
   501  		return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0])
   502  	}
   503  	packet = packet[1:]
   504  
   505  	n, packet, ok := parseUint32(packet)
   506  	if !ok || int(n) != len(questions) {
   507  		return nil, parseError(msgUserAuthInfoResponse)
   508  	}
   509  
   510  	for i := uint32(0); i < n; i++ {
   511  		ans, rest, ok := parseString(packet)
   512  		if !ok {
   513  			return nil, parseError(msgUserAuthInfoResponse)
   514  		}
   515  
   516  		answers = append(answers, string(ans))
   517  		packet = rest
   518  	}
   519  	if len(packet) != 0 {
   520  		return nil, errors.New("ssh: junk at end of message")
   521  	}
   522  
   523  	return answers, nil
   524  }