-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample_server.act
More file actions
90 lines (71 loc) · 3.04 KB
/
Copy pathexample_server.act
File metadata and controls
90 lines (71 loc) · 3.04 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
"""Example SSH server: password auth + a tiny exec command handler.
Build: acton build
Run: ./out/bin/example_server [PORT] [USER] [PASSWORD]
Defaults: PORT 2222, USER "demo", PASSWORD "demo". PORT 0 picks an ephemeral
port (printed on startup). A fresh in-memory host key is generated each run.
Try it with the bundled client (or OpenSSH):
./out/bin/example_server 2222 demo demo &
./out/bin/example_client 127.0.0.1 demo "hello world" 2222 demo
ssh -p 2222 demo@127.0.0.1 "hello world" # password: demo
The exec handler echoes the command back and exits 0; an interactive shell
request is declined. This shows the full server surface: on_auth,
on_channel_open, on_exec, and the write/exit/close channel lifecycle.
"""
import net
import lib as ssh
actor main(env):
port = u16(int(env.argv[1])) if len(env.argv) > 1 else u16(2222)
user = env.argv[2] if len(env.argv) > 2 else "demo"
password = env.argv[3] if len(env.argv) > 3 else "demo"
var server: ?ssh.Server = None
def on_listen(s: ssh.Server, err: ?str):
if err is not None:
print("listen error:", err)
env.exit(1)
return
p = await async s.bound_port()
print("listening on 127.0.0.1:" + str(p) + " (user=" + user + ")")
def on_server_close(s: ssh.Server, reason: str):
print("server closed:", reason)
env.exit(0)
def on_session(sess: ssh.ServerSession):
print("session established")
def on_session_close(sess: ssh.ServerSession, reason: str):
print("session closed:", reason)
def on_auth(sess: ssh.ServerSession, req: ssh.AuthRequest):
# This example only accepts password auth. To accept keys instead,
# compare req.pubkey (an authorized_keys "<type> <base64>" line)
# against an authorized set when req.method == "publickey".
if req.method == "password" and req.user == user and req.password == password:
print("auth ok for", req.user)
sess.accept_auth()
else:
print("auth rejected for", req.user, "(" + req.method + ")")
sess.reject_auth("denied")
def srv_on_data(ch: ssh.ServerChannel, data: ?bytes):
pass
def srv_on_stderr(ch: ssh.ServerChannel, data: ?bytes):
pass
def srv_on_close(ch: ssh.ServerChannel, reason: str):
pass
def on_channel_open(sess: ssh.ServerSession):
sess.accept_channel(ssh.ServerChannel(sess, srv_on_data, srv_on_stderr, srv_on_close))
def on_exec(sess: ssh.ServerSession, ch: ssh.ServerChannel, cmd: str):
print("exec:", cmd)
ch.accept_request()
ch.write(("you ran: " + cmd + "\n").encode())
ch.send_exit_status(0)
ch.close()
server = ssh.Server(
net.TCPListenCap(net.TCPCap(net.NetCap(env.cap))),
"127.0.0.1",
port,
on_listen,
on_server_close,
on_session,
on_auth,
on_channel_open,
on_exec,
on_session_close=on_session_close,
)
# The server runs until the process is stopped (e.g. Ctrl-C).