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 }