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