-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
125 lines (104 loc) · 2.6 KB
/
main.go
File metadata and controls
125 lines (104 loc) · 2.6 KB
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
package main
import (
"crypto/rand"
"crypto/rsa"
"encoding/json"
"io"
"log"
"net"
"os"
"os/exec"
"golang.org/x/crypto/ssh"
)
func HandleError(err error) {
if err != nil {
log.Fatalln(err)
}
}
var userconfig struct {
Address string
PrivateKeyPath string
BinPath string
}
func init() {
bytes, err := os.ReadFile("config.json")
HandleError(err)
HandleError(json.Unmarshal(bytes, &userconfig))
}
func generateRandomSigner() ssh.Signer {
privkey, err := rsa.GenerateKey(rand.Reader, 2048)
HandleError(err)
signer, err := ssh.NewSignerFromKey(privkey)
HandleError(err)
return signer
}
var serverconfig *ssh.ServerConfig
func init() {
serverconfig = &ssh.ServerConfig{
PasswordCallback: func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
return nil, nil
},
}
var signer ssh.Signer
privkeybytes, err := os.ReadFile(userconfig.PrivateKeyPath)
if err == nil {
signer, err = ssh.ParsePrivateKey(privkeybytes)
HandleError(err)
} else {
log.Println("The private key file either was not supplied or can not be opened, falling back to randomly generated private key.")
signer = generateRandomSigner()
}
serverconfig.AddHostKey(signer)
}
func supplyEnvironmentVariables(_ ssh.Channel, cmd *exec.Cmd) {
// Also supply password, client key, client username/id
// but afaik that's not even possible with the current state of x/crypto/ssh
cmd.Env = []string{"PATH=" + userconfig.BinPath}
}
func spawnProcess(channel ssh.Channel) {
cmd := exec.Command(userconfig.BinPath)
supplyEnvironmentVariables(channel, cmd)
stdinp, err := cmd.StdinPipe()
HandleError(err)
stdoup, err := cmd.StdoutPipe()
HandleError(err)
go io.Copy(stdinp, channel)
go io.Copy(channel, stdoup)
log.Println("Spawning process: ", userconfig.BinPath)
HandleError(cmd.Run())
log.Println("Done")
}
func handleConnection(nConn net.Conn) {
_, chans, reqs, err := ssh.NewServerConn(nConn, serverconfig)
HandleError(err)
go ssh.DiscardRequests(reqs)
for newChannel := range chans {
if newChannel.ChannelType() != "session" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
continue
}
channel, requests, err := newChannel.Accept()
HandleError(err)
go func(in <-chan *ssh.Request) {
for req := range in {
if req.WantReply {
req.Reply(true, nil)
}
}
}(requests)
go func() {
defer channel.Close()
spawnProcess(channel)
}()
}
}
func main() {
listener, err := net.Listen("tcp", userconfig.Address)
HandleError(err)
defer listener.Close()
for {
nConn, err := listener.Accept()
HandleError(err)
go handleConnection(nConn)
}
}