/
ssh.go
126 lines (103 loc) · 2.77 KB
/
ssh.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package main
import (
"encoding/base64"
"errors"
"fmt"
"golang.org/x/crypto/ssh"
"io/ioutil"
"os"
"time"
)
var (
hostPrivateKeySigner ssh.Signer
)
func init() {
keyPath := "./host_key"
if os.Getenv("HOST_KEY") != "" {
keyPath = os.Getenv("HOST_KEY")
}
hostPrivateKey, err := ioutil.ReadFile(keyPath)
if err != nil {
panic(err)
}
hostPrivateKeySigner, err = ssh.ParsePrivateKey(hostPrivateKey)
if err != nil {
panic(err)
}
}
func isValidToken(s string) bool {
if len(s) != tokenLength {
return false
}
for _, c := range s {
if c > 127 {
return false
} else if !(c >= 65 && c <= 90) && !(c >= 97 && c <= 122) {
return false
}
}
return true
}
func keyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
log.Println(conn.RemoteAddr(), "authenticate with", key.Type(), "for user", conn.User())
log.Println(base64.StdEncoding.EncodeToString(key.Marshal()))
if isValidToken(conn.User()) {
authRequestMap.Lock()
authRequestMap.matches[conn.User()] = key.Type() + " " + base64.StdEncoding.EncodeToString(key.Marshal())
authRequestMap.timestamps[conn.User()] = time.Now()
authRequestMap.Unlock()
return nil, nil
}
//Causes "Permission denied (publickey)." for openssh. How can this bubble up to the user?
return nil, errors.New("Invalid token/username.")
}
func handleRequests(reqs <-chan *ssh.Request) {
for req := range reqs {
log.Printf("received out-of-band request: %+v", req)
}
}
func handleChannels(chans <-chan ssh.NewChannel) {
// Service the incoming Channel channel.
for newChannel := range chans {
// Channels have a type, depending on the application level
// protocol intended. In the case of a shell, the type is
// "session" and ServerShell may be used to present a simple
// terminal interface.
if t := newChannel.ChannelType(); t != "session" {
newChannel.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t))
continue
}
channel, requests, err := newChannel.Accept()
if err != nil {
log.Printf("could not accept channel (%s)", err)
continue
}
// Sessions have out-of-band requests such as "shell", "pty-req" and "env"
go func(in <-chan *ssh.Request) {
for req := range in {
//log.Printf("%v %s", req.Payload, req.Payload)
ok := false
switch req.Type {
case "exec":
ok = false
case "shell":
req.Reply(true, nil)
channel.Write([]byte("Auth request received. "))
channel.Close()
channel.CloseWrite()
return
case "pty-req":
// Responding 'ok' here will let the client
// know we have a pty ready for input
ok = true
case "window-change":
continue //no response
}
if !ok {
log.Printf("declining %s request...", req.Type)
}
req.Reply(ok, nil)
}
}(requests)
}
}