ssh.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. // Prototype, git client looks like do not recognize req.Reply.
  5. package ssh
  6. import (
  7. "fmt"
  8. "io/ioutil"
  9. "net"
  10. "os"
  11. "os/exec"
  12. "strings"
  13. "github.com/Unknwon/com"
  14. "golang.org/x/crypto/ssh"
  15. "github.com/gogits/gogs/modules/log"
  16. )
  17. func handleServerConn(keyId string, chans <-chan ssh.NewChannel) {
  18. for newChan := range chans {
  19. if newChan.ChannelType() != "session" {
  20. newChan.Reject(ssh.UnknownChannelType, "unknown channel type")
  21. continue
  22. }
  23. channel, requests, err := newChan.Accept()
  24. if err != nil {
  25. log.Error(3, "Could not accept channel: %v", err)
  26. continue
  27. }
  28. go func(in <-chan *ssh.Request) {
  29. defer channel.Close()
  30. for req := range in {
  31. ok, payload := false, strings.TrimLeft(string(req.Payload), "\x00&")
  32. fmt.Println("Request:", req.Type, req.WantReply, payload)
  33. if req.WantReply {
  34. fmt.Println(req.Reply(true, nil))
  35. }
  36. switch req.Type {
  37. case "env":
  38. args := strings.Split(strings.Replace(payload, "\x00", "", -1), "\v")
  39. if len(args) != 2 {
  40. break
  41. }
  42. args[0] = strings.TrimLeft(args[0], "\x04")
  43. _, _, err := com.ExecCmdBytes("env", args[0]+"="+args[1])
  44. if err != nil {
  45. log.Error(3, "env: %v", err)
  46. channel.Stderr().Write([]byte(err.Error()))
  47. break
  48. }
  49. ok = true
  50. case "exec":
  51. os.Setenv("SSH_ORIGINAL_COMMAND", strings.TrimLeft(payload, "'("))
  52. log.Info("Payload: %v", strings.TrimLeft(payload, "'("))
  53. cmd := exec.Command("/Users/jiahuachen/Applications/Go/src/github.com/gogits/gogs/gogs", "serv", "key-"+keyId)
  54. cmd.Stdout = channel
  55. cmd.Stdin = channel
  56. cmd.Stderr = channel.Stderr()
  57. if err := cmd.Run(); err != nil {
  58. log.Error(3, "exec: %v", err)
  59. } else {
  60. ok = true
  61. }
  62. }
  63. fmt.Println("Done:", ok)
  64. }
  65. fmt.Println("Done!!!")
  66. }(requests)
  67. }
  68. }
  69. func listen(config *ssh.ServerConfig, port string) {
  70. listener, err := net.Listen("tcp", "0.0.0.0:"+port)
  71. if err != nil {
  72. panic(err)
  73. }
  74. for {
  75. // Once a ServerConfig has been configured, connections can be accepted.
  76. conn, err := listener.Accept()
  77. if err != nil {
  78. log.Error(3, "Fail to accept incoming connection: %v", err)
  79. continue
  80. }
  81. // Before use, a handshake must be performed on the incoming net.Conn.
  82. sConn, chans, reqs, err := ssh.NewServerConn(conn, config)
  83. if err != nil {
  84. log.Error(3, "Fail to handshake: %v", err)
  85. continue
  86. }
  87. // The incoming Request channel must be serviced.
  88. go ssh.DiscardRequests(reqs)
  89. go handleServerConn(sConn.Permissions.Extensions["key-id"], chans)
  90. }
  91. }
  92. // Listen starts a SSH server listens on given port.
  93. func Listen(port string) {
  94. config := &ssh.ServerConfig{
  95. PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
  96. // keyCache[string(ssh.MarshalAuthorizedKey(key))] = 2
  97. return &ssh.Permissions{Extensions: map[string]string{"key-id": "1"}}, nil
  98. },
  99. }
  100. privateBytes, err := ioutil.ReadFile("/Users/jiahuachen/.ssh/id_rsa")
  101. if err != nil {
  102. panic("failed to load private key")
  103. }
  104. private, err := ssh.ParsePrivateKey(privateBytes)
  105. if err != nil {
  106. panic("failed to parse private key")
  107. }
  108. config.AddHostKey(private)
  109. go listen(config, port)
  110. }