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