Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package ssh | 5 package ssh |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "crypto" | 9 "crypto" |
10 "crypto/rand" | 10 "crypto/rand" |
(...skipping 24 matching lines...) Expand all Loading... | |
35 // PasswordCallback, if non-nil, is called when a user attempts to | 35 // PasswordCallback, if non-nil, is called when a user attempts to |
36 // authenticate using a password. It may be called concurrently from | 36 // authenticate using a password. It may be called concurrently from |
37 // several goroutines. | 37 // several goroutines. |
38 PasswordCallback func(conn *ServerConn, user, password string) bool | 38 PasswordCallback func(conn *ServerConn, user, password string) bool |
39 | 39 |
40 // PublicKeyCallback, if non-nil, is called when a client attempts publi c | 40 // PublicKeyCallback, if non-nil, is called when a client attempts publi c |
41 // key authentication. It must return true iff the given public key is | 41 // key authentication. It must return true iff the given public key is |
42 // valid for the given user. | 42 // valid for the given user. |
43 PublicKeyCallback func(conn *ServerConn, user, algo string, pubkey []byt e) bool | 43 PublicKeyCallback func(conn *ServerConn, user, algo string, pubkey []byt e) bool |
44 | 44 |
45 // ChallengeResponseCallback, if non-nil, is called when | |
46 // keyboard-interactive authentication is selected (RFC | |
47 // 4256). The client object's Challenge function should be | |
48 // used to query the user. The callback may offer multiple | |
49 // Challenge rounds. To avoid information leaks, the client | |
agl1
2013/06/06 14:22:13
only a single space after a period. (several cases
hanwen-google
2013/06/06 14:37:17
Done.
| |
50 // should be presented a challenge even if the user is | |
51 // unknown. | |
52 ChallengeResponseCallback func(conn *ServerConn, user string, client Cli entChallengeResponse) bool | |
53 | |
45 // Cryptographic-related configuration. | 54 // Cryptographic-related configuration. |
46 Crypto CryptoConfig | 55 Crypto CryptoConfig |
47 } | 56 } |
48 | 57 |
49 func (c *ServerConfig) rand() io.Reader { | 58 func (c *ServerConfig) rand() io.Reader { |
50 if c.Rand == nil { | 59 if c.Rand == nil { |
51 return rand.Reader | 60 return rand.Reader |
52 } | 61 } |
53 return c.Rand | 62 return c.Rand |
54 } | 63 } |
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
408 payload = payload[1:] | 417 payload = payload[1:] |
409 password, payload, ok := parseString(payload) | 418 password, payload, ok := parseString(payload) |
410 if !ok || len(payload) > 0 { | 419 if !ok || len(payload) > 0 { |
411 return ParseError{msgUserAuthRequest} | 420 return ParseError{msgUserAuthRequest} |
412 } | 421 } |
413 | 422 |
414 s.User = userAuthReq.User | 423 s.User = userAuthReq.User |
415 if s.config.PasswordCallback(s, userAuthReq.User, string (password)) { | 424 if s.config.PasswordCallback(s, userAuthReq.User, string (password)) { |
416 break userAuthLoop | 425 break userAuthLoop |
417 } | 426 } |
427 case "keyboard-interactive": | |
428 if s.config.ChallengeResponseCallback == nil { | |
429 break | |
430 } | |
431 | |
432 s.User = userAuthReq.User | |
433 ok := s.config.ChallengeResponseCallback(s, s.User, &ssh ClientChallengeResponse{s}) | |
agl1
2013/06/06 14:22:13
merge this with following conditional.
hanwen-google
2013/06/06 14:37:17
Done.
| |
434 if ok { | |
435 break userAuthLoop | |
436 } | |
418 case "publickey": | 437 case "publickey": |
419 if s.config.PublicKeyCallback == nil { | 438 if s.config.PublicKeyCallback == nil { |
420 break | 439 break |
421 } | 440 } |
422 payload := userAuthReq.Payload | 441 payload := userAuthReq.Payload |
423 if len(payload) < 1 { | 442 if len(payload) < 1 { |
424 return ParseError{msgUserAuthRequest} | 443 return ParseError{msgUserAuthRequest} |
425 } | 444 } |
426 isQuery := payload[0] == 0 | 445 isQuery := payload[0] == 0 |
427 payload = payload[1:] | 446 payload = payload[1:] |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
491 } | 510 } |
492 } | 511 } |
493 | 512 |
494 var failureMsg userAuthFailureMsg | 513 var failureMsg userAuthFailureMsg |
495 if s.config.PasswordCallback != nil { | 514 if s.config.PasswordCallback != nil { |
496 failureMsg.Methods = append(failureMsg.Methods, "passwor d") | 515 failureMsg.Methods = append(failureMsg.Methods, "passwor d") |
497 } | 516 } |
498 if s.config.PublicKeyCallback != nil { | 517 if s.config.PublicKeyCallback != nil { |
499 failureMsg.Methods = append(failureMsg.Methods, "publick ey") | 518 failureMsg.Methods = append(failureMsg.Methods, "publick ey") |
500 } | 519 } |
520 if s.config.ChallengeResponseCallback != nil { | |
521 failureMsg.Methods = append(failureMsg.Methods, "keyboar d-interactive") | |
522 } | |
501 | 523 |
502 if len(failureMsg.Methods) == 0 { | 524 if len(failureMsg.Methods) == 0 { |
503 return errors.New("ssh: no authentication methods config ured but NoClientAuth is also false") | 525 return errors.New("ssh: no authentication methods config ured but NoClientAuth is also false") |
504 } | 526 } |
505 | 527 |
506 if err = s.writePacket(marshal(msgUserAuthFailure, failureMsg)); err != nil { | 528 if err = s.writePacket(marshal(msgUserAuthFailure, failureMsg)); err != nil { |
507 return err | 529 return err |
508 } | 530 } |
509 } | 531 } |
510 | 532 |
511 packet = []byte{msgUserAuthSuccess} | 533 packet = []byte{msgUserAuthSuccess} |
512 if err = s.writePacket(packet); err != nil { | 534 if err = s.writePacket(packet); err != nil { |
513 return err | 535 return err |
514 } | 536 } |
515 | 537 |
516 return nil | 538 return nil |
517 } | 539 } |
518 | 540 |
541 // sshClientChallengeResponse implements a ClientChallengeResponse by | |
542 // asking the client on the other side of a ServerConn. | |
543 type sshClientChallengeResponse struct { | |
544 *ServerConn | |
545 } | |
546 | |
547 func (c *sshClientChallengeResponse) Challenge(user, instruction string, questio ns []string, echos []bool) (answers []string, err error) { | |
548 if len(questions) != len(echos) { | |
549 return nil, errors.New("ssh: echos and questions must have equal length") | |
550 } | |
551 | |
552 var prompts []byte | |
553 for i := range questions { | |
554 prompts = appendString(prompts, questions[i]) | |
555 prompts = appendBool(prompts, echos[i]) | |
556 } | |
557 | |
558 if err := c.writePacket(marshal(msgUserAuthInfoRequest, userAuthInfoRequ estMsg{ | |
559 Instruction: instruction, | |
560 NumPrompts: uint32(len(questions)), | |
561 Prompts: prompts, | |
562 })); err != nil { | |
563 return nil, err | |
564 } | |
565 | |
566 packet, err := c.readPacket() | |
567 if err != nil { | |
568 return nil, err | |
569 } | |
570 if packet[0] != msgUserAuthInfoResponse { | |
571 return nil, UnexpectedMessageError{msgUserAuthInfoResponse, pack et[0]} | |
572 } | |
573 packet = packet[1:] | |
574 | |
575 var n uint32 | |
agl1
2013/06/06 14:22:13
it seems that these two var lines can be eliminate
hanwen-google
2013/06/06 14:37:17
Done.
| |
576 var ok bool | |
577 n, packet, ok = parseUint32(packet) | |
578 if !ok || int(n) != len(questions) { | |
579 return nil, &ParseError{msgUserAuthInfoResponse} | |
580 } | |
581 | |
582 for i := uint32(0); i < n; i++ { | |
583 ans, rest, ok := parseString(packet) | |
584 if !ok { | |
585 return nil, &ParseError{msgUserAuthInfoResponse} | |
586 } | |
587 | |
588 answers = append(answers, string(ans)) | |
589 packet = rest | |
590 } | |
591 if len(packet) != 0 { | |
592 return nil, errors.New("ssh: junk at end of message") | |
593 } | |
594 | |
595 return answers, nil | |
596 } | |
597 | |
519 const defaultWindowSize = 32768 | 598 const defaultWindowSize = 32768 |
520 | 599 |
521 // Accept reads and processes messages on a ServerConn. It must be called | 600 // Accept reads and processes messages on a ServerConn. It must be called |
522 // in order to demultiplex messages to any resulting Channels. | 601 // in order to demultiplex messages to any resulting Channels. |
523 func (s *ServerConn) Accept() (Channel, error) { | 602 func (s *ServerConn) Accept() (Channel, error) { |
524 // TODO(dfc) s.lock is not held here so visibility of s.err is not guara nteed. | 603 // TODO(dfc) s.lock is not held here so visibility of s.err is not guara nteed. |
525 if s.err != nil { | 604 if s.err != nil { |
526 return nil, s.err | 605 return nil, s.err |
527 } | 606 } |
528 | 607 |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
689 func Listen(network, addr string, config *ServerConfig) (*Listener, error) { | 768 func Listen(network, addr string, config *ServerConfig) (*Listener, error) { |
690 l, err := net.Listen(network, addr) | 769 l, err := net.Listen(network, addr) |
691 if err != nil { | 770 if err != nil { |
692 return nil, err | 771 return nil, err |
693 } | 772 } |
694 return &Listener{ | 773 return &Listener{ |
695 l, | 774 l, |
696 config, | 775 config, |
697 }, nil | 776 }, nil |
698 } | 777 } |
OLD | NEW |