Source File
server.go
Belonging Package
golang.org/x/crypto/ssh
package ssh
import (
)
Extensions map[string]string
}
AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error)
PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
AuthLogCallback func(conn ConnMetadata, method string, err error)
BannerCallback func(conn ConnMetadata) string
type cachedPubKey struct {
user string
pubKeyData []byte
result error
perms *Permissions
}
const maxCachedPubKeys = 16
type pubKeyCache struct {
keys []cachedPubKey
}
func ( *pubKeyCache) ( string, []byte) (cachedPubKey, bool) {
for , := range .keys {
if .user == && bytes.Equal(.pubKeyData, ) {
return , true
}
}
return cachedPubKey{}, false
}
func ( *pubKeyCache) ( cachedPubKey) {
if len(.keys) < maxCachedPubKeys {
.keys = append(.keys, )
}
}
type ServerConn struct {
Conn
func ( net.Conn, *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
:= *
.SetDefaults()
if .MaxAuthTries == 0 {
.MaxAuthTries = 6
for , := range .KeyExchanges {
if , := serverForbiddenKexAlgos[]; {
return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", )
}
}
:= &connection{
sshConn: sshConn{conn: },
}
, := .serverHandshake(&)
if != nil {
.Close()
return nil, nil, nil,
}
return &ServerConn{, }, .mux.incomingChannels, .mux.incomingRequests, nil
}
func ( *connection) ( *ServerConfig) (*Permissions, error) {
if len(.hostKeys) == 0 {
return nil, errors.New("ssh: server has no host keys")
}
if !.NoClientAuth && .PasswordCallback == nil && .PublicKeyCallback == nil &&
.KeyboardInteractiveCallback == nil && (.GSSAPIWithMICConfig == nil ||
.GSSAPIWithMICConfig.AllowLogin == nil || .GSSAPIWithMICConfig.Server == nil) {
return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
}
if .ServerVersion != "" {
.serverVersion = []byte(.ServerVersion)
} else {
.serverVersion = []byte(packageVersion)
}
var error
.clientVersion, = exchangeVersions(.sshConn.conn, .serverVersion)
if != nil {
return nil,
}
:= newTransport(.sshConn.conn, .Rand, false /* not client */)
.transport = newServerTransport(, .clientVersion, .serverVersion, )
if := .transport.waitSession(); != nil {
return nil,
}
.sessionID = .transport.getSessionID()
var []byte
if , = .transport.readPacket(); != nil {
return nil,
}
var serviceRequestMsg
if = Unmarshal(, &); != nil {
return nil,
}
if .Service != serviceUserAuth {
return nil, errors.New("ssh: requested service '" + .Service + "' before authenticating")
}
:= serviceAcceptMsg{
Service: serviceUserAuth,
}
if := .transport.writePacket(Marshal(&)); != nil {
return nil,
}
, := .serverAuthenticate()
if != nil {
return nil,
}
.mux = newMux(.transport)
return ,
}
func ( string) bool {
switch {
case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519,
CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
return true
}
return false
}
func ( net.Addr, string) error {
if == nil {
return errors.New("ssh: no address known for client, but source-address match required")
}
, := .(*net.TCPAddr)
if ! {
return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", )
}
for , := range strings.Split(, ",") {
if := net.ParseIP(); != nil {
if .Equal(.IP) {
return nil
}
} else {
, , := net.ParseCIDR()
if != nil {
return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", , )
}
if .Contains(.IP) {
return nil
}
}
}
return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", )
}
func ( *GSSAPIWithMICConfig, []byte, *connection,
[]byte, userAuthRequestMsg) ( error, *Permissions, error) {
:= .Server
defer .DeleteSecContext()
var string
for {
var (
[]byte
bool
)
, , , = .AcceptSecContext()
if != nil {
return , nil, nil
}
if len() != 0 {
if := .transport.writePacket(Marshal(&userAuthGSSAPIToken{
Token: ,
})); != nil {
return nil, nil,
}
}
if ! {
break
}
, := .transport.readPacket()
if != nil {
return nil, nil,
}
:= &userAuthGSSAPIToken{}
if := Unmarshal(, ); != nil {
return nil, nil,
}
}
, := .transport.readPacket()
if != nil {
return nil, nil,
}
:= &userAuthGSSAPIMIC{}
if := Unmarshal(, ); != nil {
return nil, nil,
}
:= buildMIC(string(), .User, .Service, .Method)
if := .VerifyMIC(, .MIC); != nil {
return , nil, nil
}
, = .AllowLogin(, )
return , , nil
}
var ErrNoAuth = errors.New("ssh: no auth passed yet")
func ( *connection) ( *ServerConfig) (*Permissions, error) {
:= .transport.getSessionID()
var pubKeyCache
var *Permissions
:= 0
var []error
var bool
:
for {
if >= .MaxAuthTries && .MaxAuthTries > 0 {
:= &disconnectMsg{
Reason: 2,
Message: "too many authentication failures",
}
if := .transport.writePacket(Marshal()); != nil {
return nil,
}
return nil,
}
var userAuthRequestMsg
if , := .transport.readPacket(); != nil {
if == io.EOF {
return nil, &ServerAuthError{Errors: }
}
return nil,
} else if = Unmarshal(, &); != nil {
return nil,
}
if .Service != serviceSSH {
return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + .Service)
}
.user = .User
if ! && .BannerCallback != nil {
= true
:= .BannerCallback()
if != "" {
:= &userAuthBannerMsg{
Message: ,
}
if := .transport.writePacket(Marshal()); != nil {
return nil,
}
}
}
= nil
:= ErrNoAuth
switch .Method {
case "none":
if .NoClientAuth {
= nil
}
if == 0 {
--
}
case "password":
if .PasswordCallback == nil {
= errors.New("ssh: password auth not configured")
break
}
:= .Payload
if len() < 1 || [0] != 0 {
return nil, parseError(msgUserAuthRequest)
}
= [1:]
, , := parseString()
if ! || len() > 0 {
return nil, parseError(msgUserAuthRequest)
}
, = .PasswordCallback(, )
case "keyboard-interactive":
if .KeyboardInteractiveCallback == nil {
= errors.New("ssh: keyboard-interactive auth not configured")
break
}
:= &sshClientKeyboardInteractive{}
, = .KeyboardInteractiveCallback(, .Challenge)
case "publickey":
if .PublicKeyCallback == nil {
= errors.New("ssh: publickey auth not configured")
break
}
:= .Payload
if len() < 1 {
return nil, parseError(msgUserAuthRequest)
}
:= [0] == 0
= [1:]
, , := parseString()
if ! {
return nil, parseError(msgUserAuthRequest)
}
:= string()
if !isAcceptableAlgo() {
= fmt.Errorf("ssh: algorithm %q not accepted", )
break
}
, , := parseString()
if ! {
return nil, parseError(msgUserAuthRequest)
}
, := ParsePublicKey()
if != nil {
return nil,
}
, := .get(.user, )
if ! {
.user = .user
.pubKeyData =
.perms, .result = .PublicKeyCallback(, )
if .result == nil && .perms != nil && .perms.CriticalOptions != nil && .perms.CriticalOptions[sourceAddressCriticalOption] != "" {
.result = checkSourceAddress(
.RemoteAddr(),
.perms.CriticalOptions[sourceAddressCriticalOption])
}
.add()
}
if len() > 0 {
return nil, parseError(msgUserAuthRequest)
}
if .result == nil {
:= userAuthPubKeyOkMsg{
Algo: ,
PubKey: ,
}
if = .transport.writePacket(Marshal(&)); != nil {
return nil,
}
continue
}
= .result
} else {
, , := parseSignature()
if ! || len() > 0 {
return nil, parseError(msgUserAuthRequest)
if !isAcceptableAlgo(.Format) {
= fmt.Errorf("ssh: algorithm %q not accepted", .Format)
break
}
:= buildDataSignedForAuth(, , , )
if := .Verify(, ); != nil {
return nil,
}
= .result
= .perms
}
case "gssapi-with-mic":
if .GSSAPIWithMICConfig == nil {
= errors.New("ssh: gssapi-with-mic auth not configured")
break
}
:= .GSSAPIWithMICConfig
, := parseGSSAPIPayload(.Payload)
if != nil {
return nil, parseError(msgUserAuthRequest)
if := .transport.writePacket(Marshal(&userAuthGSSAPIResponse{
SupportMech: krb5OID,
})); != nil {
return nil,
, := .transport.readPacket()
if != nil {
return nil,
}
:= &userAuthGSSAPIToken{}
if := Unmarshal(, ); != nil {
return nil,
}
, , = gssExchangeToken(, .Token, , ,
)
if != nil {
return nil,
}
default:
= fmt.Errorf("ssh: unknown method %q", .Method)
}
= append(, )
if .AuthLogCallback != nil {
.AuthLogCallback(, .Method, )
}
if == nil {
break
}
++
var userAuthFailureMsg
if .PasswordCallback != nil {
.Methods = append(.Methods, "password")
}
if .PublicKeyCallback != nil {
.Methods = append(.Methods, "publickey")
}
if .KeyboardInteractiveCallback != nil {
.Methods = append(.Methods, "keyboard-interactive")
}
if .GSSAPIWithMICConfig != nil && .GSSAPIWithMICConfig.Server != nil &&
.GSSAPIWithMICConfig.AllowLogin != nil {
.Methods = append(.Methods, "gssapi-with-mic")
}
if len(.Methods) == 0 {
return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
}
if := .transport.writePacket(Marshal(&)); != nil {
return nil,
}
}
if := .transport.writePacket([]byte{msgUserAuthSuccess}); != nil {
return nil,
}
return , nil
}
type sshClientKeyboardInteractive struct {
*connection
}
func ( *sshClientKeyboardInteractive) (, string, []string, []bool) ( []string, error) {
if len() != len() {
return nil, errors.New("ssh: echos and questions must have equal length")
}
var []byte
for := range {
= appendString(, [])
= appendBool(, [])
}
if := .transport.writePacket(Marshal(&userAuthInfoRequestMsg{
Instruction: ,
NumPrompts: uint32(len()),
Prompts: ,
})); != nil {
return nil,
}
, := .transport.readPacket()
if != nil {
return nil,
}
if [0] != msgUserAuthInfoResponse {
return nil, unexpectedMessageError(msgUserAuthInfoResponse, [0])
}
= [1:]
, , := parseUint32()
if ! || int() != len() {
return nil, parseError(msgUserAuthInfoResponse)
}
for := uint32(0); < ; ++ {
, , := parseString()
if ! {
return nil, parseError(msgUserAuthInfoResponse)
}
= append(, string())
=
}
if len() != 0 {
return nil, errors.New("ssh: junk at end of message")
}
return , nil
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |