Copyright 2011 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package ssh

import (
	
	
	
	
)

type authResult int

const (
	authFailure authResult = iota
	authPartialSuccess
	authSuccess
)
clientAuthenticate authenticates with the remote server. See RFC 4252.
initiate user auth session
	if  := .transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth}));  != nil {
		return 
	}
	,  := .transport.readPacket()
	if  != nil {
		return 
	}
	var  serviceAcceptMsg
	if  := Unmarshal(, &);  != nil {
		return 
	}
during the authentication phase the client first attempts the "none" method then any untried methods suggested by the server.
	var  []string
	var  []string

	 := .transport.getSessionID()
	for  := AuthMethod(new(noneAuth));  != nil; {
		, ,  := .auth(, .User, .transport, .Rand)
		if  != nil {
			return 
		}
success
			return nil
		} else if  == authFailure {
			if  := .method(); !contains(, ) {
				 = append(, )
			}
		}
		if  == nil {
			 = 
		}
		 = 

		 = nil

	:
		for ,  := range .Auth {
			 := .method()
			if contains(, ) {
				continue
			}
			for ,  := range  {
				if  ==  {
					 = 
					break 
				}
			}
		}
	}
	return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", )
}

func ( []string,  string) bool {
	for ,  := range  {
		if  ==  {
			return true
		}
	}
	return false
}
An AuthMethod represents an instance of an RFC 4252 authentication method.
auth authenticates user over transport t. Returns true if authentication is successful. If authentication is not successful, a []string of alternative method names is returned. If the slice is nil, it will be ignored and the previous set of possible methods will be reused.
	auth(session []byte, user string, p packetConn, rand io.Reader) (authResult, []string, error)
method returns the RFC 4252 method name.
	method() string
}
"none" authentication, RFC 4252 section 5.2.
type noneAuth int

func ( *noneAuth) ( []byte,  string,  packetConn,  io.Reader) (authResult, []string, error) {
	if  := .writePacket(Marshal(&userAuthRequestMsg{
		User:    ,
		Service: serviceSSH,
		Method:  "none",
	}));  != nil {
		return authFailure, nil, 
	}

	return handleAuthResponse()
}

func ( *noneAuth) () string {
	return "none"
}
passwordCallback is an AuthMethod that fetches the password through a function call, e.g. by prompting the user.
type passwordCallback func() (password string, err error)

func ( passwordCallback) ( []byte,  string,  packetConn,  io.Reader) (authResult, []string, error) {
	type  struct {
		     string `sshtype:"50"`
		  string
		   string
		    bool
		 string
	}

REVIEW NOTE: is there a need to support skipping a password attempt? The program may only find out that the user doesn't have a password when prompting.
	if  != nil {
		return authFailure, nil, 
	}

	if  := .writePacket(Marshal(&{
		:     ,
		:  serviceSSH,
		:   .method(),
		:    false,
		: ,
	}));  != nil {
		return authFailure, nil, 
	}

	return handleAuthResponse()
}

func ( passwordCallback) () string {
	return "password"
}
Password returns an AuthMethod using the given password.
func ( string) AuthMethod {
	return passwordCallback(func() (string, error) { return , nil })
}
PasswordCallback returns an AuthMethod that uses a callback for fetching a password.
func ( func() ( string,  error)) AuthMethod {
	return passwordCallback()
}

type publickeyAuthMsg struct {
	User    string `sshtype:"50"`
	Service string
HasSig indicates to the receiver packet that the auth request is signed and should be used for authentication of the request.
Sig is tagged with "rest" so Marshal will exclude it during validateKey
	Sig []byte `ssh:"rest"`
}
publicKeyCallback is an AuthMethod that uses a set of key pairs for authentication.
type publicKeyCallback func() ([]Signer, error)

func ( publicKeyCallback) () string {
	return "publickey"
}

Authentication is performed by sending an enquiry to test if a key is acceptable to the remote. If the key is acceptable, the client will attempt to authenticate with the valid key. If not the client will repeat the process with the remaining keys.

	,  := ()
	if  != nil {
		return authFailure, nil, 
	}
	var  []string
	for ,  := range  {
		,  := validateKey(.PublicKey(), , )
		if  != nil {
			return authFailure, nil, 
		}
		if ! {
			continue
		}

		 := .PublicKey()
		 := .Marshal()
		,  := .Sign(, buildDataSignedForAuth(, userAuthRequestMsg{
			User:    ,
			Service: serviceSSH,
			Method:  .method(),
		}, []byte(.Type()), ))
		if  != nil {
			return authFailure, nil, 
		}
manually wrap the serialized signature in a string
		 := Marshal()
		 := make([]byte, stringLength(len()))
		marshalString(, )
		 := publickeyAuthMsg{
			User:     ,
			Service:  serviceSSH,
			Method:   .method(),
			HasSig:   true,
			Algoname: .Type(),
			PubKey:   ,
			Sig:      ,
		}
		 := Marshal(&)
		if  := .writePacket();  != nil {
			return authFailure, nil, 
		}
		var  authResult
		, ,  = handleAuthResponse()
		if  != nil {
			return authFailure, nil, 
		}
If authentication succeeds or the list of available methods does not contain the "publickey" method, do not attempt to authenticate with any other keys. According to RFC 4252 Section 7, the latter can occur when additional authentication methods are required.
		if  == authSuccess || !containsMethod(, .method()) {
			return , , 
		}
	}

	return authFailure, , nil
}

func ( []string,  string) bool {
	for ,  := range  {
		if  ==  {
			return true
		}
	}

	return false
}
validateKey validates the key provided is acceptable to the server.
func ( PublicKey,  string,  packetConn) (bool, error) {
	 := .Marshal()
	 := publickeyAuthMsg{
		User:     ,
		Service:  serviceSSH,
		Method:   "publickey",
		HasSig:   false,
		Algoname: .Type(),
		PubKey:   ,
	}
	if  := .writePacket(Marshal(&));  != nil {
		return false, 
	}

	return confirmKeyAck(, )
}

func ( PublicKey,  packetConn) (bool, error) {
	 := .Marshal()
	 := .Type()

	for {
		,  := .readPacket()
		if  != nil {
			return false, 
		}
		switch [0] {
		case msgUserAuthBanner:
			if  := handleBannerResponse(, );  != nil {
				return false, 
			}
		case msgUserAuthPubKeyOk:
			var  userAuthPubKeyOkMsg
			if  := Unmarshal(, &);  != nil {
				return false, 
			}
			if .Algo !=  || !bytes.Equal(.PubKey, ) {
				return false, nil
			}
			return true, nil
		case msgUserAuthFailure:
			return false, nil
		default:
			return false, unexpectedMessageError(msgUserAuthSuccess, [0])
		}
	}
}
PublicKeys returns an AuthMethod that uses the given key pairs.
func ( ...Signer) AuthMethod {
	return publicKeyCallback(func() ([]Signer, error) { return , nil })
}
PublicKeysCallback returns an AuthMethod that runs the given function to obtain a list of key pairs.
func ( func() ( []Signer,  error)) AuthMethod {
	return publicKeyCallback()
}
handleAuthResponse returns whether the preceding authentication request succeeded along with a list of remaining authentication methods to try next and an error if an unexpected response was received.
func ( packetConn) (authResult, []string, error) {
	for {
		,  := .readPacket()
		if  != nil {
			return authFailure, nil, 
		}

		switch [0] {
		case msgUserAuthBanner:
			if  := handleBannerResponse(, );  != nil {
				return authFailure, nil, 
			}
		case msgUserAuthFailure:
			var  userAuthFailureMsg
			if  := Unmarshal(, &);  != nil {
				return authFailure, nil, 
			}
			if .PartialSuccess {
				return authPartialSuccess, .Methods, nil
			}
			return authFailure, .Methods, nil
		case msgUserAuthSuccess:
			return authSuccess, nil, nil
		default:
			return authFailure, nil, unexpectedMessageError(msgUserAuthSuccess, [0])
		}
	}
}

func ( packetConn,  []byte) error {
	var  userAuthBannerMsg
	if  := Unmarshal(, &);  != nil {
		return 
	}

	,  := .(*handshakeTransport)
	if ! {
		return nil
	}

	if .bannerCallback != nil {
		return .bannerCallback(.Message)
	}

	return nil
}
KeyboardInteractiveChallenge should print questions, optionally disabling echoing (e.g. for passwords), and return all the answers. Challenge may be called multiple times in a single session. After successful authentication, the server may send a challenge with no questions, for which the user and instruction messages should be printed. RFC 4256 section 3.3 details how the UI should behave for both CLI and GUI environments.
type KeyboardInteractiveChallenge func(user, instruction string, questions []string, echos []bool) (answers []string, err error)
KeyboardInteractive returns an AuthMethod using a prompt/response sequence controlled by the server.
func ( KeyboardInteractiveChallenge) AuthMethod {
	return 
}

func ( KeyboardInteractiveChallenge) () string {
	return "keyboard-interactive"
}

func ( KeyboardInteractiveChallenge) ( []byte,  string,  packetConn,  io.Reader) (authResult, []string, error) {
	type  struct {
		       string `sshtype:"50"`
		    string
		     string
		   string
		 string
	}

	if  := .writePacket(Marshal(&{
		:    ,
		: serviceSSH,
		:  "keyboard-interactive",
	}));  != nil {
		return authFailure, nil, 
	}

	for {
		,  := .readPacket()
		if  != nil {
			return authFailure, nil, 
		}
like handleAuthResponse, but with less options.
		switch [0] {
		case msgUserAuthBanner:
			if  := handleBannerResponse(, );  != nil {
				return authFailure, nil, 
			}
			continue
OK
		case msgUserAuthFailure:
			var  userAuthFailureMsg
			if  := Unmarshal(, &);  != nil {
				return authFailure, nil, 
			}
			if .PartialSuccess {
				return authPartialSuccess, .Methods, nil
			}
			return authFailure, .Methods, nil
		case msgUserAuthSuccess:
			return authSuccess, nil, nil
		default:
			return authFailure, nil, unexpectedMessageError(msgUserAuthInfoRequest, [0])
		}

		var  userAuthInfoRequestMsg
		if  := Unmarshal(, &);  != nil {
			return authFailure, nil, 
		}
Manually unpack the prompt/echo pairs.
		 := .Prompts
		var  []string
		var  []bool
		for  := 0;  < int(.NumPrompts); ++ {
			, ,  := parseString()
			if ! || len() == 0 {
				return authFailure, nil, errors.New("ssh: prompt format error")
			}
			 = append(, string())
			 = append(, [0] != 0)
			 = [1:]
		}

		if len() != 0 {
			return authFailure, nil, errors.New("ssh: extra data following keyboard-interactive pairs")
		}

		,  := (.User, .Instruction, , )
		if  != nil {
			return authFailure, nil, 
		}

		if len() != len() {
			return authFailure, nil, fmt.Errorf("ssh: incorrect number of answers from keyboard-interactive callback %d (expected %d)", len(), len())
		}
		 := 1 + 4
		for ,  := range  {
			 += stringLength(len())
		}
		 := make([]byte, )
		 := 
		[0] = msgUserAuthInfoResponse
		 = [1:]
		 = marshalUint32(, uint32(len()))
		for ,  := range  {
			 = marshalString(, []byte())
		}

		if  := .writePacket();  != nil {
			return authFailure, nil, 
		}
	}
}

type retryableAuthMethod struct {
	authMethod AuthMethod
	maxTries   int
}

func ( *retryableAuthMethod) ( []byte,  string,  packetConn,  io.Reader) ( authResult,  []string,  error) {
	for  := 0; .maxTries <= 0 ||  < .maxTries; ++ {
		, ,  = .authMethod.auth(, , , )
		if  != authFailure ||  != nil { // either success, partial success or error terminate
			return , , 
		}
	}
	return , , 
}

func ( *retryableAuthMethod) () string {
	return .authMethod.method()
}
RetryableAuthMethod is a decorator for other auth methods enabling them to be retried up to maxTries before considering that AuthMethod itself failed. If maxTries is <= 0, will retry indefinitely This is useful for interactive clients using challenge/response type authentication (e.g. Keyboard-Interactive, Password, etc) where the user could mistype their response resulting in the server issuing a SSH_MSG_USERAUTH_FAILURE (rfc4252 #8 [password] and rfc4256 #3.4 [keyboard-interactive]); Without this decorator, the non-retryable AuthMethod would be removed from future consideration, and never tried again (and so the user would never be able to retry their entry).
func ( AuthMethod,  int) AuthMethod {
	return &retryableAuthMethod{authMethod: , maxTries: }
}
GSSAPIWithMICAuthMethod is an AuthMethod with "gssapi-with-mic" authentication. See RFC 4462 section 3 gssAPIClient is implementation of the GSSAPIClient interface, see the definition of the interface for details. target is the server host you want to log in to.
func ( GSSAPIClient,  string) AuthMethod {
	if  == nil {
		panic("gss-api client must be not nil with enable gssapi-with-mic")
	}
	return &gssAPIWithMICCallback{gssAPIClient: , target: }
}

type gssAPIWithMICCallback struct {
	gssAPIClient GSSAPIClient
	target       string
}

func ( *gssAPIWithMICCallback) ( []byte,  string,  packetConn,  io.Reader) (authResult, []string, error) {
	 := &userAuthRequestMsg{
		User:    ,
		Service: serviceSSH,
		Method:  .method(),
The GSS-API authentication method is initiated when the client sends an SSH_MSG_USERAUTH_REQUEST. See RFC 4462 section 3.2.
	.Payload = appendU32(.Payload, 1)
	.Payload = appendString(.Payload, string(krb5OID))
	if  := .writePacket(Marshal());  != nil {
		return authFailure, nil, 
The server responds to the SSH_MSG_USERAUTH_REQUEST with either an SSH_MSG_USERAUTH_FAILURE if none of the mechanisms are supported or with an SSH_MSG_USERAUTH_GSSAPI_RESPONSE. See RFC 4462 section 3.3. OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication,so I don't want to check selected mech if it is valid.
	,  := .readPacket()
	if  != nil {
		return authFailure, nil, 
	}
	 := &userAuthGSSAPIResponse{}
	if  := Unmarshal(, );  != nil {
		return authFailure, nil, 
Start the loop into the exchange token. See RFC 4462 section 3.4.
	var  []byte
	defer .gssAPIClient.DeleteSecContext()
Initiates the establishment of a security context between the application and a remote peer.
		, ,  := .gssAPIClient.InitSecContext("host@"+.target, , false)
		if  != nil {
			return authFailure, nil, 
		}
		if len() > 0 {
			if  := .writePacket(Marshal(&userAuthGSSAPIToken{
				Token: ,
			}));  != nil {
				return authFailure, nil, 
			}
		}
		if ! {
			break
		}
		,  = .readPacket()
		if  != nil {
			return authFailure, nil, 
		}
		switch [0] {
		case msgUserAuthFailure:
			var  userAuthFailureMsg
			if  := Unmarshal(, &);  != nil {
				return authFailure, nil, 
			}
			if .PartialSuccess {
				return authPartialSuccess, .Methods, nil
			}
			return authFailure, .Methods, nil
		case msgUserAuthGSSAPIError:
			 := &userAuthGSSAPIError{}
			if  := Unmarshal(, );  != nil {
				return authFailure, nil, 
			}
			return authFailure, nil, fmt.Errorf("GSS-API Error:\n"+
				"Major Status: %d\n"+
				"Minor Status: %d\n"+
				"Error Message: %s\n", .MajorStatus, .MinorStatus,
				.Message)
		case msgUserAuthGSSAPIToken:
			 := &userAuthGSSAPIToken{}
			if  := Unmarshal(, );  != nil {
				return authFailure, nil, 
			}
			 = .Token
		}
Binding Encryption Keys. See RFC 4462 section 3.5.
	 := buildMIC(string(), , "ssh-connection", "gssapi-with-mic")
	,  := .gssAPIClient.GetMIC()
	if  != nil {
		return authFailure, nil, 
	}
	if  := .writePacket(Marshal(&userAuthGSSAPIMIC{
		MIC: ,
	}));  != nil {
		return authFailure, nil, 
	}
	return handleAuthResponse()
}

func ( *gssAPIWithMICCallback) () string {
	return "gssapi-with-mic"