gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

server.go (24510B)


      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 user.
     18 // The Permissions value for a successful authentication attempt is
     19 // available in ServerConn, so it can be used to pass information from
     20 // the user-authentication phase to the application layer.
     21 type Permissions struct {
     22 	// CriticalOptions indicate restrictions to the default
     23 	// permissions, and are typically used in conjunction with
     24 	// user certificates. The standard for SSH certificates
     25 	// defines "force-command" (only allow the given command to
     26 	// execute) and "source-address" (only allow connections from
     27 	// the given address). The SSH package currently only enforces
     28 	// the "source-address" critical option. It is up to server
     29 	// implementations to enforce other critical options, such as
     30 	// "force-command", by checking them after the SSH handshake
     31 	// is successful. In general, SSH servers should reject
     32 	// connections that specify critical options that are unknown
     33 	// or not supported.
     34 	CriticalOptions map[string]string
     35 
     36 	// Extensions are extra functionality that the server may
     37 	// offer on authenticated connections. Lack of support for an
     38 	// extension does not preclude authenticating a user. Common
     39 	// extensions are "permit-agent-forwarding",
     40 	// "permit-X11-forwarding". The Go SSH library currently does
     41 	// not act on any extension, and it is up to server
     42 	// implementations to honor them. Extensions can be used to
     43 	// pass data from the authentication callbacks to the server
     44 	// application layer.
     45 	Extensions map[string]string
     46 }
     47 
     48 type GSSAPIWithMICConfig struct {
     49 	// AllowLogin, must be set, is called when gssapi-with-mic
     50 	// authentication is selected (RFC 4462 section 3). The srcName is from the
     51 	// results of the GSS-API authentication. The format is username@DOMAIN.
     52 	// GSSAPI just guarantees to the server who the user is, but not if they can log in, and with what permissions.
     53 	// This callback is called after the user identity is established with GSSAPI to decide if the user can login with
     54 	// which permissions. If the user is allowed to login, it should return a nil error.
     55 	AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error)
     56 
     57 	// Server must be set. It's the implementation
     58 	// of the GSSAPIServer interface. See GSSAPIServer interface for details.
     59 	Server GSSAPIServer
     60 }
     61 
     62 // ServerConfig holds server specific configuration data.
     63 type ServerConfig struct {
     64 	// Config contains configuration shared between client and server.
     65 	Config
     66 
     67 	hostKeys []Signer
     68 
     69 	// NoClientAuth is true if clients are allowed to connect without
     70 	// authenticating.
     71 	// To determine NoClientAuth at runtime, set NoClientAuth to true
     72 	// and the optional NoClientAuthCallback to a non-nil value.
     73 	NoClientAuth bool
     74 
     75 	// NoClientAuthCallback, if non-nil, is called when a user
     76 	// attempts to authenticate with auth method "none".
     77 	// NoClientAuth must also be set to true for this be used, or
     78 	// this func is unused.
     79 	NoClientAuthCallback func(ConnMetadata) (*Permissions, error)
     80 
     81 	// MaxAuthTries specifies the maximum number of authentication attempts
     82 	// permitted per connection. If set to a negative number, the number of
     83 	// attempts are unlimited. If set to zero, the number of attempts are limited
     84 	// to 6.
     85 	MaxAuthTries int
     86 
     87 	// PasswordCallback, if non-nil, is called when a user
     88 	// attempts to authenticate using a password.
     89 	PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
     90 
     91 	// PublicKeyCallback, if non-nil, is called when a client
     92 	// offers a public key for authentication. It must return a nil error
     93 	// if the given public key can be used to authenticate the
     94 	// given user. For example, see CertChecker.Authenticate. A
     95 	// call to this function does not guarantee that the key
     96 	// offered is in fact used to authenticate. To record any data
     97 	// depending on the public key, store it inside a
     98 	// Permissions.Extensions entry.
     99 	PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
    100 
    101 	// KeyboardInteractiveCallback, if non-nil, is called when
    102 	// keyboard-interactive authentication is selected (RFC
    103 	// 4256). The client object's Challenge function should be
    104 	// used to query the user. The callback may offer multiple
    105 	// Challenge rounds. To avoid information leaks, the client
    106 	// should be presented a challenge even if the user is
    107 	// unknown.
    108 	KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
    109 
    110 	// AuthLogCallback, if non-nil, is called to log all authentication
    111 	// attempts.
    112 	AuthLogCallback func(conn ConnMetadata, method string, err error)
    113 
    114 	// ServerVersion is the version identification string to announce in
    115 	// the public handshake.
    116 	// If empty, a reasonable default is used.
    117 	// Note that RFC 4253 section 4.2 requires that this string start with
    118 	// "SSH-2.0-".
    119 	ServerVersion string
    120 
    121 	// BannerCallback, if present, is called and the return string is sent to
    122 	// the client after key exchange completed but before authentication.
    123 	BannerCallback func(conn ConnMetadata) string
    124 
    125 	// GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used
    126 	// when gssapi-with-mic authentication is selected (RFC 4462 section 3).
    127 	GSSAPIWithMICConfig *GSSAPIWithMICConfig
    128 }
    129 
    130 // AddHostKey adds a private key as a host key. If an existing host
    131 // key exists with the same public key format, it is replaced. Each server
    132 // config must have at least one host key.
    133 func (s *ServerConfig) AddHostKey(key Signer) {
    134 	for i, k := range s.hostKeys {
    135 		if k.PublicKey().Type() == key.PublicKey().Type() {
    136 			s.hostKeys[i] = key
    137 			return
    138 		}
    139 	}
    140 
    141 	s.hostKeys = append(s.hostKeys, key)
    142 }
    143 
    144 // cachedPubKey contains the results of querying whether a public key is
    145 // acceptable for a user.
    146 type cachedPubKey struct {
    147 	user       string
    148 	pubKeyData []byte
    149 	result     error
    150 	perms      *Permissions
    151 }
    152 
    153 const maxCachedPubKeys = 16
    154 
    155 // pubKeyCache caches tests for public keys.  Since SSH clients
    156 // will query whether a public key is acceptable before attempting to
    157 // authenticate with it, we end up with duplicate queries for public
    158 // key validity.  The cache only applies to a single ServerConn.
    159 type pubKeyCache struct {
    160 	keys []cachedPubKey
    161 }
    162 
    163 // get returns the result for a given user/algo/key tuple.
    164 func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
    165 	for _, k := range c.keys {
    166 		if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) {
    167 			return k, true
    168 		}
    169 	}
    170 	return cachedPubKey{}, false
    171 }
    172 
    173 // add adds the given tuple to the cache.
    174 func (c *pubKeyCache) add(candidate cachedPubKey) {
    175 	if len(c.keys) < maxCachedPubKeys {
    176 		c.keys = append(c.keys, candidate)
    177 	}
    178 }
    179 
    180 // ServerConn is an authenticated SSH connection, as seen from the
    181 // server
    182 type ServerConn struct {
    183 	Conn
    184 
    185 	// If the succeeding authentication callback returned a
    186 	// non-nil Permissions pointer, it is stored here.
    187 	Permissions *Permissions
    188 }
    189 
    190 // NewServerConn starts a new SSH server with c as the underlying
    191 // transport.  It starts with a handshake and, if the handshake is
    192 // unsuccessful, it closes the connection and returns an error.  The
    193 // Request and NewChannel channels must be serviced, or the connection
    194 // will hang.
    195 //
    196 // The returned error may be of type *ServerAuthError for
    197 // authentication errors.
    198 func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
    199 	fullConf := *config
    200 	fullConf.SetDefaults()
    201 	if fullConf.MaxAuthTries == 0 {
    202 		fullConf.MaxAuthTries = 6
    203 	}
    204 	// Check if the config contains any unsupported key exchanges
    205 	for _, kex := range fullConf.KeyExchanges {
    206 		if _, ok := serverForbiddenKexAlgos[kex]; ok {
    207 			return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
    208 		}
    209 	}
    210 
    211 	s := &connection{
    212 		sshConn: sshConn{conn: c},
    213 	}
    214 	perms, err := s.serverHandshake(&fullConf)
    215 	if err != nil {
    216 		c.Close()
    217 		return nil, nil, nil, err
    218 	}
    219 	return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil
    220 }
    221 
    222 // signAndMarshal signs the data with the appropriate algorithm,
    223 // and serializes the result in SSH wire format. algo is the negotiate
    224 // algorithm and may be a certificate type.
    225 func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo string) ([]byte, error) {
    226 	sig, err := k.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
    227 	if err != nil {
    228 		return nil, err
    229 	}
    230 
    231 	return Marshal(sig), nil
    232 }
    233 
    234 // handshake performs key exchange and user authentication.
    235 func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) {
    236 	if len(config.hostKeys) == 0 {
    237 		return nil, errors.New("ssh: server has no host keys")
    238 	}
    239 
    240 	if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil &&
    241 		config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil ||
    242 		config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) {
    243 		return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
    244 	}
    245 
    246 	if config.ServerVersion != "" {
    247 		s.serverVersion = []byte(config.ServerVersion)
    248 	} else {
    249 		s.serverVersion = []byte(packageVersion)
    250 	}
    251 	var err error
    252 	s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
    253 	if err != nil {
    254 		return nil, err
    255 	}
    256 
    257 	tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */)
    258 	s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
    259 
    260 	if err := s.transport.waitSession(); err != nil {
    261 		return nil, err
    262 	}
    263 
    264 	// We just did the key change, so the session ID is established.
    265 	s.sessionID = s.transport.getSessionID()
    266 
    267 	var packet []byte
    268 	if packet, err = s.transport.readPacket(); err != nil {
    269 		return nil, err
    270 	}
    271 
    272 	var serviceRequest serviceRequestMsg
    273 	if err = Unmarshal(packet, &serviceRequest); err != nil {
    274 		return nil, err
    275 	}
    276 	if serviceRequest.Service != serviceUserAuth {
    277 		return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
    278 	}
    279 	serviceAccept := serviceAcceptMsg{
    280 		Service: serviceUserAuth,
    281 	}
    282 	if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
    283 		return nil, err
    284 	}
    285 
    286 	perms, err := s.serverAuthenticate(config)
    287 	if err != nil {
    288 		return nil, err
    289 	}
    290 	s.mux = newMux(s.transport)
    291 	return perms, err
    292 }
    293 
    294 func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
    295 	if addr == nil {
    296 		return errors.New("ssh: no address known for client, but source-address match required")
    297 	}
    298 
    299 	tcpAddr, ok := addr.(*net.TCPAddr)
    300 	if !ok {
    301 		return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
    302 	}
    303 
    304 	for _, sourceAddr := range strings.Split(sourceAddrs, ",") {
    305 		if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
    306 			if allowedIP.Equal(tcpAddr.IP) {
    307 				return nil
    308 			}
    309 		} else {
    310 			_, ipNet, err := net.ParseCIDR(sourceAddr)
    311 			if err != nil {
    312 				return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
    313 			}
    314 
    315 			if ipNet.Contains(tcpAddr.IP) {
    316 				return nil
    317 			}
    318 		}
    319 	}
    320 
    321 	return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
    322 }
    323 
    324 func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection,
    325 	sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
    326 	gssAPIServer := gssapiConfig.Server
    327 	defer gssAPIServer.DeleteSecContext()
    328 	var srcName string
    329 	for {
    330 		var (
    331 			outToken     []byte
    332 			needContinue bool
    333 		)
    334 		outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken)
    335 		if err != nil {
    336 			return err, nil, nil
    337 		}
    338 		if len(outToken) != 0 {
    339 			if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{
    340 				Token: outToken,
    341 			})); err != nil {
    342 				return nil, nil, err
    343 			}
    344 		}
    345 		if !needContinue {
    346 			break
    347 		}
    348 		packet, err := s.transport.readPacket()
    349 		if err != nil {
    350 			return nil, nil, err
    351 		}
    352 		userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
    353 		if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
    354 			return nil, nil, err
    355 		}
    356 	}
    357 	packet, err := s.transport.readPacket()
    358 	if err != nil {
    359 		return nil, nil, err
    360 	}
    361 	userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{}
    362 	if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil {
    363 		return nil, nil, err
    364 	}
    365 	mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method)
    366 	if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil {
    367 		return err, nil, nil
    368 	}
    369 	perms, authErr = gssapiConfig.AllowLogin(s, srcName)
    370 	return authErr, perms, nil
    371 }
    372 
    373 // ServerAuthError represents server authentication errors and is
    374 // sometimes returned by NewServerConn. It appends any authentication
    375 // errors that may occur, and is returned if all of the authentication
    376 // methods provided by the user failed to authenticate.
    377 type ServerAuthError struct {
    378 	// Errors contains authentication errors returned by the authentication
    379 	// callback methods. The first entry is typically ErrNoAuth.
    380 	Errors []error
    381 }
    382 
    383 func (l ServerAuthError) Error() string {
    384 	var errs []string
    385 	for _, err := range l.Errors {
    386 		errs = append(errs, err.Error())
    387 	}
    388 	return "[" + strings.Join(errs, ", ") + "]"
    389 }
    390 
    391 // ErrNoAuth is the error value returned if no
    392 // authentication method has been passed yet. This happens as a normal
    393 // part of the authentication loop, since the client first tries
    394 // 'none' authentication to discover available methods.
    395 // It is returned in ServerAuthError.Errors from NewServerConn.
    396 var ErrNoAuth = errors.New("ssh: no auth passed yet")
    397 
    398 func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
    399 	sessionID := s.transport.getSessionID()
    400 	var cache pubKeyCache
    401 	var perms *Permissions
    402 
    403 	authFailures := 0
    404 	var authErrs []error
    405 	var displayedBanner bool
    406 
    407 userAuthLoop:
    408 	for {
    409 		if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
    410 			discMsg := &disconnectMsg{
    411 				Reason:  2,
    412 				Message: "too many authentication failures",
    413 			}
    414 
    415 			if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
    416 				return nil, err
    417 			}
    418 
    419 			return nil, discMsg
    420 		}
    421 
    422 		var userAuthReq userAuthRequestMsg
    423 		if packet, err := s.transport.readPacket(); err != nil {
    424 			if err == io.EOF {
    425 				return nil, &ServerAuthError{Errors: authErrs}
    426 			}
    427 			return nil, err
    428 		} else if err = Unmarshal(packet, &userAuthReq); err != nil {
    429 			return nil, err
    430 		}
    431 
    432 		if userAuthReq.Service != serviceSSH {
    433 			return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
    434 		}
    435 
    436 		s.user = userAuthReq.User
    437 
    438 		if !displayedBanner && config.BannerCallback != nil {
    439 			displayedBanner = true
    440 			msg := config.BannerCallback(s)
    441 			if msg != "" {
    442 				bannerMsg := &userAuthBannerMsg{
    443 					Message: msg,
    444 				}
    445 				if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil {
    446 					return nil, err
    447 				}
    448 			}
    449 		}
    450 
    451 		perms = nil
    452 		authErr := ErrNoAuth
    453 
    454 		switch userAuthReq.Method {
    455 		case "none":
    456 			if config.NoClientAuth {
    457 				if config.NoClientAuthCallback != nil {
    458 					perms, authErr = config.NoClientAuthCallback(s)
    459 				} else {
    460 					authErr = nil
    461 				}
    462 			}
    463 
    464 			// allow initial attempt of 'none' without penalty
    465 			if authFailures == 0 {
    466 				authFailures--
    467 			}
    468 		case "password":
    469 			if config.PasswordCallback == nil {
    470 				authErr = errors.New("ssh: password auth not configured")
    471 				break
    472 			}
    473 			payload := userAuthReq.Payload
    474 			if len(payload) < 1 || payload[0] != 0 {
    475 				return nil, parseError(msgUserAuthRequest)
    476 			}
    477 			payload = payload[1:]
    478 			password, payload, ok := parseString(payload)
    479 			if !ok || len(payload) > 0 {
    480 				return nil, parseError(msgUserAuthRequest)
    481 			}
    482 
    483 			perms, authErr = config.PasswordCallback(s, password)
    484 		case "keyboard-interactive":
    485 			if config.KeyboardInteractiveCallback == nil {
    486 				authErr = errors.New("ssh: keyboard-interactive auth not configured")
    487 				break
    488 			}
    489 
    490 			prompter := &sshClientKeyboardInteractive{s}
    491 			perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge)
    492 		case "publickey":
    493 			if config.PublicKeyCallback == nil {
    494 				authErr = errors.New("ssh: publickey auth not configured")
    495 				break
    496 			}
    497 			payload := userAuthReq.Payload
    498 			if len(payload) < 1 {
    499 				return nil, parseError(msgUserAuthRequest)
    500 			}
    501 			isQuery := payload[0] == 0
    502 			payload = payload[1:]
    503 			algoBytes, payload, ok := parseString(payload)
    504 			if !ok {
    505 				return nil, parseError(msgUserAuthRequest)
    506 			}
    507 			algo := string(algoBytes)
    508 			if !contains(supportedPubKeyAuthAlgos, underlyingAlgo(algo)) {
    509 				authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
    510 				break
    511 			}
    512 
    513 			pubKeyData, payload, ok := parseString(payload)
    514 			if !ok {
    515 				return nil, parseError(msgUserAuthRequest)
    516 			}
    517 
    518 			pubKey, err := ParsePublicKey(pubKeyData)
    519 			if err != nil {
    520 				return nil, err
    521 			}
    522 
    523 			candidate, ok := cache.get(s.user, pubKeyData)
    524 			if !ok {
    525 				candidate.user = s.user
    526 				candidate.pubKeyData = pubKeyData
    527 				candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey)
    528 				if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
    529 					candidate.result = checkSourceAddress(
    530 						s.RemoteAddr(),
    531 						candidate.perms.CriticalOptions[sourceAddressCriticalOption])
    532 				}
    533 				cache.add(candidate)
    534 			}
    535 
    536 			if isQuery {
    537 				// The client can query if the given public key
    538 				// would be okay.
    539 
    540 				if len(payload) > 0 {
    541 					return nil, parseError(msgUserAuthRequest)
    542 				}
    543 
    544 				if candidate.result == nil {
    545 					okMsg := userAuthPubKeyOkMsg{
    546 						Algo:   algo,
    547 						PubKey: pubKeyData,
    548 					}
    549 					if err = s.transport.writePacket(Marshal(&okMsg)); err != nil {
    550 						return nil, err
    551 					}
    552 					continue userAuthLoop
    553 				}
    554 				authErr = candidate.result
    555 			} else {
    556 				sig, payload, ok := parseSignature(payload)
    557 				if !ok || len(payload) > 0 {
    558 					return nil, parseError(msgUserAuthRequest)
    559 				}
    560 
    561 				// Ensure the public key algo and signature algo
    562 				// are supported.  Compare the private key
    563 				// algorithm name that corresponds to algo with
    564 				// sig.Format.  This is usually the same, but
    565 				// for certs, the names differ.
    566 				if !contains(supportedPubKeyAuthAlgos, sig.Format) {
    567 					authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
    568 					break
    569 				}
    570 				if underlyingAlgo(algo) != sig.Format {
    571 					authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo)
    572 					break
    573 				}
    574 
    575 				signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData)
    576 
    577 				if err := pubKey.Verify(signedData, sig); err != nil {
    578 					return nil, err
    579 				}
    580 
    581 				authErr = candidate.result
    582 				perms = candidate.perms
    583 			}
    584 		case "gssapi-with-mic":
    585 			if config.GSSAPIWithMICConfig == nil {
    586 				authErr = errors.New("ssh: gssapi-with-mic auth not configured")
    587 				break
    588 			}
    589 			gssapiConfig := config.GSSAPIWithMICConfig
    590 			userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
    591 			if err != nil {
    592 				return nil, parseError(msgUserAuthRequest)
    593 			}
    594 			// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication.
    595 			if userAuthRequestGSSAPI.N == 0 {
    596 				authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported")
    597 				break
    598 			}
    599 			var i uint32
    600 			present := false
    601 			for i = 0; i < userAuthRequestGSSAPI.N; i++ {
    602 				if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) {
    603 					present = true
    604 					break
    605 				}
    606 			}
    607 			if !present {
    608 				authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism")
    609 				break
    610 			}
    611 			// Initial server response, see RFC 4462 section 3.3.
    612 			if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{
    613 				SupportMech: krb5OID,
    614 			})); err != nil {
    615 				return nil, err
    616 			}
    617 			// Exchange token, see RFC 4462 section 3.4.
    618 			packet, err := s.transport.readPacket()
    619 			if err != nil {
    620 				return nil, err
    621 			}
    622 			userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
    623 			if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
    624 				return nil, err
    625 			}
    626 			authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID,
    627 				userAuthReq)
    628 			if err != nil {
    629 				return nil, err
    630 			}
    631 		default:
    632 			authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
    633 		}
    634 
    635 		authErrs = append(authErrs, authErr)
    636 
    637 		if config.AuthLogCallback != nil {
    638 			config.AuthLogCallback(s, userAuthReq.Method, authErr)
    639 		}
    640 
    641 		if authErr == nil {
    642 			break userAuthLoop
    643 		}
    644 
    645 		authFailures++
    646 		if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries {
    647 			// If we have hit the max attempts, don't bother sending the
    648 			// final SSH_MSG_USERAUTH_FAILURE message, since there are
    649 			// no more authentication methods which can be attempted,
    650 			// and this message may cause the client to re-attempt
    651 			// authentication while we send the disconnect message.
    652 			// Continue, and trigger the disconnect at the start of
    653 			// the loop.
    654 			//
    655 			// The SSH specification is somewhat confusing about this,
    656 			// RFC 4252 Section 5.1 requires each authentication failure
    657 			// be responded to with a respective SSH_MSG_USERAUTH_FAILURE
    658 			// message, but Section 4 says the server should disconnect
    659 			// after some number of attempts, but it isn't explicit which
    660 			// message should take precedence (i.e. should there be a failure
    661 			// message than a disconnect message, or if we are going to
    662 			// disconnect, should we only send that message.)
    663 			//
    664 			// Either way, OpenSSH disconnects immediately after the last
    665 			// failed authnetication attempt, and given they are typically
    666 			// considered the golden implementation it seems reasonable
    667 			// to match that behavior.
    668 			continue
    669 		}
    670 
    671 		var failureMsg userAuthFailureMsg
    672 		if config.PasswordCallback != nil {
    673 			failureMsg.Methods = append(failureMsg.Methods, "password")
    674 		}
    675 		if config.PublicKeyCallback != nil {
    676 			failureMsg.Methods = append(failureMsg.Methods, "publickey")
    677 		}
    678 		if config.KeyboardInteractiveCallback != nil {
    679 			failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
    680 		}
    681 		if config.GSSAPIWithMICConfig != nil && config.GSSAPIWithMICConfig.Server != nil &&
    682 			config.GSSAPIWithMICConfig.AllowLogin != nil {
    683 			failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
    684 		}
    685 
    686 		if len(failureMsg.Methods) == 0 {
    687 			return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
    688 		}
    689 
    690 		if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil {
    691 			return nil, err
    692 		}
    693 	}
    694 
    695 	if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil {
    696 		return nil, err
    697 	}
    698 	return perms, nil
    699 }
    700 
    701 // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
    702 // asking the client on the other side of a ServerConn.
    703 type sshClientKeyboardInteractive struct {
    704 	*connection
    705 }
    706 
    707 func (c *sshClientKeyboardInteractive) Challenge(name, instruction string, questions []string, echos []bool) (answers []string, err error) {
    708 	if len(questions) != len(echos) {
    709 		return nil, errors.New("ssh: echos and questions must have equal length")
    710 	}
    711 
    712 	var prompts []byte
    713 	for i := range questions {
    714 		prompts = appendString(prompts, questions[i])
    715 		prompts = appendBool(prompts, echos[i])
    716 	}
    717 
    718 	if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
    719 		Name:        name,
    720 		Instruction: instruction,
    721 		NumPrompts:  uint32(len(questions)),
    722 		Prompts:     prompts,
    723 	})); err != nil {
    724 		return nil, err
    725 	}
    726 
    727 	packet, err := c.transport.readPacket()
    728 	if err != nil {
    729 		return nil, err
    730 	}
    731 	if packet[0] != msgUserAuthInfoResponse {
    732 		return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0])
    733 	}
    734 	packet = packet[1:]
    735 
    736 	n, packet, ok := parseUint32(packet)
    737 	if !ok || int(n) != len(questions) {
    738 		return nil, parseError(msgUserAuthInfoResponse)
    739 	}
    740 
    741 	for i := uint32(0); i < n; i++ {
    742 		ans, rest, ok := parseString(packet)
    743 		if !ok {
    744 			return nil, parseError(msgUserAuthInfoResponse)
    745 		}
    746 
    747 		answers = append(answers, string(ans))
    748 		packet = rest
    749 	}
    750 	if len(packet) != 0 {
    751 		return nil, errors.New("ssh: junk at end of message")
    752 	}
    753 
    754 	return answers, nil
    755 }