summaryrefslogtreecommitdiff
path: root/appl/cmd/ssh
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/ssh')
-rw-r--r--appl/cmd/ssh/authpassword.b68
-rw-r--r--appl/cmd/ssh/authrsa.b188
-rw-r--r--appl/cmd/ssh/authtis.b119
-rw-r--r--appl/cmd/ssh/cipher3des.b51
-rw-r--r--appl/cmd/ssh/cipherblowfish.b43
-rw-r--r--appl/cmd/ssh/cipherdes.b43
-rw-r--r--appl/cmd/ssh/ciphernone.b28
-rw-r--r--appl/cmd/ssh/cipherrc4.b46
-rw-r--r--appl/cmd/ssh/mkfile29
-rw-r--r--appl/cmd/ssh/sshio.b586
-rw-r--r--appl/cmd/ssh/sshio.m194
-rw-r--r--appl/cmd/ssh/sshserve.b495
12 files changed, 0 insertions, 1890 deletions
diff --git a/appl/cmd/ssh/authpassword.b b/appl/cmd/ssh/authpassword.b
deleted file mode 100644
index 1a149117..00000000
--- a/appl/cmd/ssh/authpassword.b
+++ /dev/null
@@ -1,68 +0,0 @@
-implement Auth;
-
-include "sys.m";
- sys: Sys;
-
-include "ipints.m";
- ipints: IPints;
- IPint: import ipints;
-
-include "crypt.m";
- crypt: Crypt; # TO DO: needed to avoid compiler error
-
-include "factotum.m";
- factotum: Factotum;
-
-include "sshio.m";
- sshio: Sshio;
- Conn, Msg: import sshio;
-
-id(): int
-{
- return SSH_AUTH_PASSWORD;
-}
-
-init(mod: Sshio)
-{
- sys = load Sys Sys->PATH;
- sshio = mod;
-}
-
-firstmsg(): int
-{
- return SSH_CMSG_AUTH_PASSWORD;
-}
-
-authsrv(c: ref Conn, m: ref Msg): ref AuthInfo
-{
- pass := m.getstring();
-# return auth_userpasswd(c.user, pass);
- return ref AuthInfo(c.user, nil); # TO DO:
-}
-
-auth(c: ref Conn): int
-{
- if(factotum == nil)
- factotum = load Factotum Factotum->PATH;
- (user, pass) := factotum->getuserpasswd(sys->sprint("proto=pass service=ssh server=%q user=%q", c.host, c.user));
- if(user == nil){
- sshio->debug(DBG_AUTH, "getuserpasswd failed");
- return -1;
- }
-
- sshio->debug(DBG_AUTH, "try using password from factotum\n");
- m := Msg.mk(SSH_CMSG_AUTH_PASSWORD, 4+Sys->UTFmax*len pass);
- m.putstring(pass);
- c.out <-= m;
-
- m = sshio->recvmsg(c, -1);
- case m.mtype {
- SSH_SMSG_SUCCESS =>
- return 0;
- SSH_SMSG_FAILURE =>
- return -1;
- * =>
- sshio->badmsg(m, 0, nil);
- return -1;
- }
-}
diff --git a/appl/cmd/ssh/authrsa.b b/appl/cmd/ssh/authrsa.b
deleted file mode 100644
index 427355d5..00000000
--- a/appl/cmd/ssh/authrsa.b
+++ /dev/null
@@ -1,188 +0,0 @@
-implement Auth;
-
-include "sys.m";
- sys: Sys;
-
-include "ipints.m";
- ipints: IPints;
- IPint: import ipints;
-
-include "crypt.m";
- crypt: Crypt;
- PK, SK: import crypt;
-
-include "factotum.m";
- factotum: Factotum;
- Attr: import factotum;
- findattrval: import factotum;
-
-include "sshio.m";
- sshio: Sshio;
- Conn, Msg: import sshio;
- debug: import sshio;
-
-id(): int
-{
- return SSH_AUTH_RSA;
-}
-
-init(mod: Sshio)
-{
- sshio = mod;
- sys = load Sys Sys->PATH;
- ipints = load IPints IPints->PATH;
- crypt = load Crypt Crypt->PATH;
- factotum = load Factotum Factotum->PATH;
- factotum->init();
-}
-
-firstmsg(): int
-{
- return SSH_CMSG_AUTH_RSA;
-}
-
-authsrv(c: ref Conn, m: ref Msg): ref AuthInfo
-{
- # TO DO: use factotum
- hismod := m.getipint();
- if(hismod.bits() < 512){
- debug(DBG_AUTH, sys->sprint("rsa key for %s < 512 bits\n", c.user));
- return nil;
- }
- hispk := readpk("/keydb/ssh/"+c.user);
- if(hispk == nil){
- debug(DBG_AUTH, sys->sprint("no ssh/rsa key for %s: %r\n", c.user));
- return nil;
- }
- if(!hispk.n.eq(hismod)){
- debug(DBG_AUTH, sys->sprint("%s rsa key doesn't match modulus\n", c.user));
- return nil;
- }
- # encrypt a challenge with his pk
-# chal := IPint.random(256).expmod(IPint.inttoip(1), hismod);
- chal := IPint.random(256);
- echal := crypt->rsaencrypt(hispk, x := sshio->rsapad(chal, (hispk.n.bits()+7)/8));
-debug(DBG_AUTH, sys->sprint("padded %s\nrsa chal %s\n", x.iptostr(16), echal.iptostr(16)));
- m = Msg.mk(SSH_SMSG_AUTH_RSA_CHALLENGE, 2048);
- m.putipint(echal);
- c.out <-= m;
-
- m = sshio->recvmsg(c, SSH_CMSG_AUTH_RSA_RESPONSE);
- response := m.getbytes(Crypt->MD5dlen);
- chalbuf := array[32+SESSIDLEN] of byte;
- sshio->iptorjustbe(chal, chalbuf, 32);
- debug(DBG_AUTH, sys->sprint("\trjusted %s\n", sshio->hex(chalbuf[0:32])));
- chalbuf[32:] = c.sessid[0: SESSIDLEN];
- debug(DBG_AUTH, sys->sprint("\tappend sessid %s\n", sshio->hex(chalbuf)));
- expected := array[Crypt->MD5dlen] of byte;
- crypt->md5(chalbuf, 32+SESSIDLEN, expected, nil);
- if(sshio->eqbytes(expected, response, len expected))
- return ref AuthInfo(c.user, nil);
- return nil;
-}
-
-readpk(file: string): ref PK.RSA
-{
- fd := sys->open(file, Sys->OREAD);
- if(fd == nil)
- return nil;
- buf := array[8192] of byte;
- nr := sys->readn(fd, buf, len buf);
- if(nr < 0)
- return nil;
- attrs := factotum->parseattrs(string buf[0: nr]);
- if(findattrval(attrs, "proto") != "rsa" ||
- (ns := findattrval(attrs, "n")) == nil ||
- (eks := findattrval(attrs, "ek")) == nil){
- sys->werrstr("missing rsa key attributes");
- return nil;
- }
- n := IPint.strtoip(ns, 16);
- ek := IPint.strtoip(eks, 16);
- if(n == nil || ek == nil){
- sys->werrstr("invalid rsa key values");
- return nil;
- }
- return ref PK.RSA(n, ek);
-}
-
-auth(c: ref Conn): int
-{
- chalbuf := array[32+SESSIDLEN] of byte;
- response := array[Crypt->MD5dlen] of byte;
-
- debug(DBG_AUTH, "authrsa\n");
-
- afd := sys->open("/mnt/factotum/rpc", Sys->ORDWR);
- if(afd == nil){
- debug(DBG_AUTH, sys->sprint("open /mnt/factotum/rpc: %r\n"));
- return -1;
- }
- s := "proto=rsa role=client";
- if(factotum->rpc(afd, "start", array of byte s).t0 != "ok"){
- debug(DBG_AUTH, sys->sprint("auth_rpc start %s failed: %r\n", s));
- return -1;
- }
-
- debug(DBG_AUTH, "trying factotum rsa keys\n");
- for(;;){
- (tag, value) := factotum->rpc(afd, "read", nil);
- if(tag != "ok")
- break;
- textkey := string value;
- sshio->debug(DBG_AUTH, sys->sprint("try %q\n", textkey));
- mod := IPint.strtoip(textkey, 16);
- m := Msg.mk(SSH_CMSG_AUTH_RSA, 16+(mod.bits()+7/8));
- m.putipint(mod);
- c.out <-= m;
-
- m = sshio->recvmsg(c, -1);
- case m.mtype {
- SSH_SMSG_FAILURE =>
- debug(DBG_AUTH, "\tnot accepted\n");
- continue;
- SSH_SMSG_AUTH_RSA_CHALLENGE =>
- ;
- * =>
- sshio->badmsg(m, 0, nil);
- }
- chal := m.getipint();
- p := chal.iptostr(16);
- debug(DBG_AUTH, sys->sprint("\tgot challenge %s\n", p));
- unpad: ref IPint;
- if(factotum->rpc(afd, "write", array of byte p).t0 == "ok" &&
- ((tag, value) = factotum->rpc(afd, "read", nil)).t0 == "ok"){
- debug(DBG_AUTH, sys->sprint("\tfactotum said %q\n", string value));
- decr := IPint.strtoip(string value, 16);
- if(decr != nil){
- debug(DBG_AUTH, sys->sprint("\tdecrypted %s\n", decr.iptostr(16)));
- unpad = sshio->rsaunpad(decr);
- }else
- unpad = IPint.inttoip(0);
- }else{
- debug(DBG_AUTH, sys->sprint("\tauth_rpc write or read failed: %r\n"));
- unpad = IPint.inttoip(0); # it will fail, we'll go round again
- }
- debug(DBG_AUTH, sys->sprint("\tunpadded %s\n", unpad.iptostr(16)));
- sshio->iptorjustbe(unpad, chalbuf, 32);
-# debug(DBG_AUTH, sys->sprint("\trjusted %.*H\n", 32, chalbuf));
- chalbuf[32:] = c.sessid[0: SESSIDLEN];
-# debug(DBG_AUTH, sys->sprint("\tappend sesskey %.*H\n", 32, chalbuf));
- crypt->md5(chalbuf, 32+SESSIDLEN, response, nil);
-
- m = Msg.mk(SSH_CMSG_AUTH_RSA_RESPONSE, Crypt->MD5dlen);
- m.putbytes(response, Crypt->MD5dlen);
- c.out <-= m;
-
- m = sshio->recvmsg(c, -1);
- case m.mtype {
- SSH_SMSG_FAILURE =>
- ; # retry
- SSH_SMSG_SUCCESS =>
- return 0;
- * =>
- sshio->badmsg(m, 0, nil);
- }
- }
- return -1;
-}
diff --git a/appl/cmd/ssh/authtis.b b/appl/cmd/ssh/authtis.b
deleted file mode 100644
index 0fd5edd6..00000000
--- a/appl/cmd/ssh/authtis.b
+++ /dev/null
@@ -1,119 +0,0 @@
-implement Auth;
-
-# TO DO: add chal/resp to Factotum
-
-include "sys.m";
- sys: Sys;
-
-include "ipints.m";
- ipints: IPints;
- IPint: import ipints;
-
-include "crypt.m";
- crypt: Crypt; # avoid compiler error
-
-include "factotum.m";
- factotum: Factotum;
- Attr: import factotum;
- findattrval: import factotum;
-
-include "sshio.m";
- sshio: Sshio;
- Conn, Msg: import sshio;
- debug: import sshio;
-
-id(): int
-{
- return SSH_AUTH_TIS;
-}
-
-init(mod: Sshio)
-{
- sshio = mod;
- sys = load Sys Sys->PATH;
- ipints = load IPints IPints->PATH;
- factotum = load Factotum Factotum->PATH;
- factotum->init();
-}
-
-firstmsg(): int
-{
- return SSH_CMSG_AUTH_TIS;
-}
-
-authsrv(conn: ref Conn, nil: ref Msg): ref AuthInfo
-{
- if((c := factotum->challenge(sys->sprint("proto=p9cr user=%q role=server", conn.user))) == nil){
-# sshlog("auth_challenge failed for %s", conn.user);
- return nil;
- }
- s := sys->sprint("Challenge: %s\nResponse: ", c.chal);
- m := Msg.mk(SSH_SMSG_AUTH_TIS_CHALLENGE, 4+len s);
- m.putstring(s);
- conn.out <-= m;
-
- m = sshio->recvmsg(conn, 0);
- if(m == nil)
- return nil;
- if(m.mtype != SSH_CMSG_AUTH_TIS_RESPONSE){
- #
- # apparently you can just give up on
- # this protocol and start a new one.
- #
- sshio->unrecvmsg(conn, m);
- return nil;
- }
-
- ai := factotum->response(c, m.getstring());
- if(ai == nil){
- debug(DBG_AUTH, sys->sprint("response rejected: %r\n"));
- return nil;
- }
- return ref AuthInfo(ai.cuid, ai.cap);
-}
-
-auth(c: ref Conn): int
-{
- if(!c.interactive)
- return -1;
-
- debug(DBG_AUTH, "try TIS\n");
- c.out <-= Msg.mk(SSH_CMSG_AUTH_TIS, 0);
-
- m := sshio->recvmsg(c, -1);
- case m.mtype {
- SSH_SMSG_FAILURE =>
- return -1;
- SSH_SMSG_AUTH_TIS_CHALLENGE =>
- ;
- * =>
- sshio->badmsg(m, SSH_SMSG_AUTH_TIS_CHALLENGE, nil);
- }
-
- chal := m.getstring();
-
- if((fd := sys->open("/dev/cons", Sys->ORDWR)) == nil)
- sshio->error(sys->sprint("can't open /dev/cons: %r"));
-
- sys->fprint(fd, "TIS Authentication\n%s", chal);
- resp := array[256] of byte;
- n := sys->read(fd, resp, len resp);
- if(n <= 0 || resp[0] == byte '\n')
- return -1;
-
- m = Msg.mk(SSH_CMSG_AUTH_TIS_RESPONSE, 4+n);
- m.put4(len resp);
- m.putbytes(resp, n);
- c.out <-= m;
-
- m = sshio->recvmsg(c, -1);
- case m.mtype {
- SSH_SMSG_SUCCESS =>
- return 0;
- SSH_SMSG_FAILURE =>
- return -1;
- * =>
- sshio->badmsg(m, 0, nil);
- return -1;
- }
-}
diff --git a/appl/cmd/ssh/cipher3des.b b/appl/cmd/ssh/cipher3des.b
deleted file mode 100644
index e6f347f1..00000000
--- a/appl/cmd/ssh/cipher3des.b
+++ /dev/null
@@ -1,51 +0,0 @@
-implement Cipher;
-
-include "sys.m";
-
-include "ipints.m";
- ipints: IPints;
- IPint: import ipints;
-
-include "crypt.m";
- crypt: Crypt;
- DESstate: import crypt;
-
-include "sshio.m";
-
-Cipherstate: adt
-{
- enc: array of ref DESstate;
- dec: array of ref DESstate;
-};
-
-cs: ref Cipherstate;
-
-id(): int
-{
- return SSH_CIPHER_3DES;
-}
-
-init(key: array of byte, nil: int)
-{
- ipints = load IPints IPints->PATH;
- crypt = load Crypt Crypt->PATH;
- cs = ref Cipherstate(array[3] of ref DESstate, array[3] of ref DESstate);
- for(i := 0; i < 3; i++){
- cs.enc[i] = crypt->dessetup(key[i*8:], nil);
- cs.dec[i] = crypt->dessetup(key[i*8:], nil);
- }
-}
-
-encrypt(buf: array of byte, nbuf: int)
-{
- crypt->descbc(cs.enc[0], buf, nbuf, Crypt->Encrypt);
- crypt->descbc(cs.enc[1], buf, nbuf, Crypt->Decrypt);
- crypt->descbc(cs.enc[2], buf, nbuf, Crypt->Encrypt);
-}
-
-decrypt(buf: array of byte, nbuf: int)
-{
- crypt->descbc(cs.dec[2], buf, nbuf, Crypt->Decrypt);
- crypt->descbc(cs.dec[1], buf, nbuf, Crypt->Encrypt);
- crypt->descbc(cs.dec[0], buf, nbuf, Crypt->Decrypt);
-}
diff --git a/appl/cmd/ssh/cipherblowfish.b b/appl/cmd/ssh/cipherblowfish.b
deleted file mode 100644
index 8d3b0c31..00000000
--- a/appl/cmd/ssh/cipherblowfish.b
+++ /dev/null
@@ -1,43 +0,0 @@
-implement Cipher;
-
-include "sys.m";
-
-include "ipints.m";
- ipints: IPints;
- IPint: import ipints;
-
-include "crypt.m";
- crypt: Crypt;
- BFstate: import crypt;
-
-include "sshio.m";
-
-Cipherstate: adt
-{
- enc: ref BFstate;
- dec: ref BFstate;
-};
-
-cs: ref Cipherstate;
-
-id(): int
-{
- return SSH_CIPHER_BLOWFISH;
-}
-
-init(key: array of byte, nil: int)
-{
- ipints = load IPints IPints->PATH;
- crypt = load Crypt Crypt->PATH;
- cs = ref Cipherstate(crypt->blowfishsetup(key, nil), crypt->blowfishsetup(key, nil));
-}
-
-encrypt(buf: array of byte, nbuf: int)
-{
- crypt->blowfishcbc(cs.enc, buf, nbuf, Crypt->Encrypt);
-}
-
-decrypt(buf: array of byte, nbuf: int)
-{
- crypt->blowfishcbc(cs.dec, buf, nbuf, Crypt->Decrypt);
-}
diff --git a/appl/cmd/ssh/cipherdes.b b/appl/cmd/ssh/cipherdes.b
deleted file mode 100644
index 7de0a7ca..00000000
--- a/appl/cmd/ssh/cipherdes.b
+++ /dev/null
@@ -1,43 +0,0 @@
-implement Cipher;
-
-include "sys.m";
-
-include "ipints.m";
- ipints: IPints;
- IPint: import ipints;
-
-include "crypt.m";
- crypt: Crypt;
- DESstate: import crypt;
-
-include "sshio.m";
-
-Cipherstate: adt
-{
- enc: ref DESstate;
- dec: ref DESstate;
-};
-
-cs: ref Cipherstate;
-
-id(): int
-{
- return SSH_CIPHER_DES;
-}
-
-init(key: array of byte, nil: int)
-{
- ipints = load IPints IPints->PATH;
- crypt = load Crypt Crypt->PATH;
- cs = ref Cipherstate(crypt->dessetup(key, nil), crypt->dessetup(key, nil));
-}
-
-encrypt(buf: array of byte, nbuf: int)
-{
- crypt->descbc(cs.enc, buf, nbuf, Crypt->Encrypt);
-}
-
-decrypt(buf: array of byte, nbuf: int)
-{
- crypt->descbc(cs.dec, buf, nbuf, Crypt->Decrypt);
-}
diff --git a/appl/cmd/ssh/ciphernone.b b/appl/cmd/ssh/ciphernone.b
deleted file mode 100644
index 01a7a1f3..00000000
--- a/appl/cmd/ssh/ciphernone.b
+++ /dev/null
@@ -1,28 +0,0 @@
-implement Cipher;
-
-include "sys.m";
-
-include "ipints.m";
- ipints: IPints;
- IPint: import ipints;
-
-include "crypt.m";
-
-include "sshio.m";
-
-id(): int
-{
- return SSH_CIPHER_NONE;
-}
-
-init(nil: array of byte, nil: int)
-{
-}
-
-encrypt(nil: array of byte, nil: int)
-{
-}
-
-decrypt(nil: array of byte, nil: int)
-{
-}
diff --git a/appl/cmd/ssh/cipherrc4.b b/appl/cmd/ssh/cipherrc4.b
deleted file mode 100644
index f43f9c8d..00000000
--- a/appl/cmd/ssh/cipherrc4.b
+++ /dev/null
@@ -1,46 +0,0 @@
-implement Cipher;
-
-include "sys.m";
-
-include "ipints.m";
- ipints: IPints;
- IPint: import ipints;
-
-include "crypt.m";
- crypt: Crypt;
- RC4state: import crypt;
-
-include "sshio.m";
-
-Cipherstate: adt
-{
- enc: ref RC4state;
- dec: ref RC4state;
-};
-
-cs: ref Cipherstate;
-
-id(): int
-{
- return SSH_CIPHER_RC4;
-}
-
-init(key: array of byte, isserver: int)
-{
- ipints = load IPints IPints->PATH;
- crypt = load Crypt Crypt->PATH;
- if(isserver)
- cs = ref Cipherstate(crypt->rc4setup(key[0:16]), crypt->rc4setup(key[16:32]));
- else
- cs = ref Cipherstate(crypt->rc4setup(key[16:32]), crypt->rc4setup(key[0:16]));
-}
-
-encrypt(buf: array of byte, nbuf: int)
-{
- crypt->rc4(cs.enc, buf, nbuf);
-}
-
-decrypt(buf: array of byte, nbuf: int)
-{
- crypt->rc4(cs.dec, buf, nbuf);
-}
diff --git a/appl/cmd/ssh/mkfile b/appl/cmd/ssh/mkfile
deleted file mode 100644
index afb4c903..00000000
--- a/appl/cmd/ssh/mkfile
+++ /dev/null
@@ -1,29 +0,0 @@
-<../../../mkconfig
-
-TARG=\
- authpassword.dis\
- authrsa.dis\
- authtis.dis\
- cipher3des.dis\
- cipherblowfish.dis\
- cipherdes.dis\
- ciphernone.dis\
- cipherrc4.dis\
- sshio.dis\
- sshserve.dis\
-# ssh.dis\
-
-SYSMODULES=\
- arg.m\
- keyring.m\
- security.m\
- rand.m\
- sys.m\
- draw.m\
-
-MODULES=\
- sshio.m\
-
-DISBIN=$ROOT/dis/ssh
-
-<$ROOT/mkfiles/mkdis
diff --git a/appl/cmd/ssh/sshio.b b/appl/cmd/ssh/sshio.b
deleted file mode 100644
index 942b06df..00000000
--- a/appl/cmd/ssh/sshio.b
+++ /dev/null
@@ -1,586 +0,0 @@
-implement Sshio;
-
-include "sys.m";
- sys: Sys;
-
-include "ipints.m";
- ipints: IPints;
- IPint: import ipints;
-
-include "crypt.m";
- crypt: Crypt;
- PK, SK: import crypt;
-
-include "sshio.m";
-
-include "rand.m";
- rand: Rand;
-
-init()
-{
- sys = load Sys Sys->PATH;
- ipints = load IPints IPints->PATH;
- crypt = load Crypt Crypt->PATH;
- rand = load Rand Rand->PATH;
- rand->init(sys->millisec());
-}
-
-msgnames := array[45] of {
- "SSH_MSG_NONE", # 0
- "SSH_MSG_DISCONNECT",
- "SSH_SMSG_PUBLIC_KEY",
- "SSH_CMSG_SESSION_KEY",
- "SSH_CMSG_USER",
- "SSH_CMSG_AUTH_RHOSTS",
- "SSH_CMSG_AUTH_RSA",
- "SSH_SMSG_AUTH_RSA_CHALLENGE",
- "SSH_CMSG_AUTH_RSA_RESPONSE",
- "SSH_CMSG_AUTH_PASSWORD",
- "SSH_CMSG_REQUEST_PTY", # 10
- "SSH_CMSG_WINDOW_SIZE",
- "SSH_CMSG_EXEC_SHELL",
- "SSH_CMSG_EXEC_CMD",
- "SSH_SMSG_SUCCESS",
- "SSH_SMSG_FAILURE",
- "SSH_CMSG_STDIN_DATA",
- "SSH_SMSG_STDOUT_DATA",
- "SSH_SMSG_STDERR_DATA",
- "SSH_CMSG_EOF",
- "SSH_SMSG_EXITSTATUS", # 20
- "SSH_MSG_CHANNEL_OPEN_CONFIRMATION",
- "SSH_MSG_CHANNEL_OPEN_FAILURE",
- "SSH_MSG_CHANNEL_DATA",
- "SSH_MSG_CHANNEL_INPUT_EOF",
- "SSH_MSG_CHANNEL_OUTPUT_CLOSED",
- "SSH_MSG_UNIX_DOMAIN_X11_FORWARDING (obsolete)",
- "SSH_SMSG_X11_OPEN",
- "SSH_CMSG_PORT_FORWARD_REQUEST",
- "SSH_MSG_PORT_OPEN",
- "SSH_CMSG_AGENT_REQUEST_FORWARDING", # 30
- "SSH_SMSG_AGENT_OPEN",
- "SSH_MSG_IGNORE",
- "SSH_CMSG_EXIT_CONFIRMATION",
- "SSH_CMSG_X11_REQUEST_FORWARDING",
- "SSH_CMSG_AUTH_RHOSTS_RSA",
- "SSH_MSG_DEBUG",
- "SSH_CMSG_REQUEST_COMPRESSION",
- "SSH_CMSG_MAX_PACKET_SIZE",
- "SSH_CMSG_AUTH_TIS",
- "SSH_SMSG_AUTH_TIS_CHALLENGE", # 40
- "SSH_CMSG_AUTH_TIS_RESPONSE",
- "SSH_CMSG_AUTH_KERBEROS",
- "SSH_SMSG_AUTH_KERBEROS_RESPONSE",
- "SSH_CMSG_HAVE_KERBEROS_TGT",
-};
-
-Conn.mk(host: string, fd: ref Sys->FD): ref Conn
-{
- c := ref Conn;
- c.host = host;
- c.sesskey = array[SESSKEYLEN] of byte;
- c.sessid = array[SESSIDLEN] of byte;
- c.in = chan of (ref Msg, string);
- c.out = chan of ref Msg;
- c.flags = 0;
- c.interactive = 0;
- sync := chan of int;
- spawn msgreader(c, fd, sync);
- <-sync;
- spawn msgwriter(c, fd, sync);
- <-sync;
- return c;
-}
-
-Conn.setkey(c: self ref Conn, key: ref PK.RSA)
-{
- c.hostkey = key;
-}
-
-msgreader(c: ref Conn, fd: ref Sys->FD, sync: chan of int)
-{
- sys->pctl(Sys->NEWFD, 2 :: fd.fd :: nil);
- sync <-= 1;
- fd = sys->fildes(fd.fd);
- for(;;){
- m := readmsg(c, fd);
- if(m == nil){
- c.in <-= (nil, sys->sprint("%r"));
- break;
- }
- debug(DBG_PROTO, sys->sprint("<-[%d] %s\n", m.ep-m.rp, m.fulltext()));
- case m.mtype {
- SSH_MSG_IGNORE =>
- ;
- SSH_MSG_DEBUG =>
- debug(DBG_PROTO, sys->sprint("remote DEBUG: %s\n", m.getstring()));
- * =>
- c.in <-= (m, nil);
- }
- }
-}
-
-msgwriter(c: ref Conn, fd: ref Sys->FD, sync: chan of int)
-{
- sys->pctl(Sys->NEWFD, 2 :: fd.fd :: nil);
- sync <-= 1;
- fd = sys->fildes(fd.fd);
- while((m := <-c.out) != nil)
- if(writemsg(c, m, fd) < 0){
- while(<-c.out != nil)
- {} # flush
- exit;
- }
-}
-
-#
-# read initial SSH-m.n-comment line
-#
-readversion(fd: ref Sys->FD): (int, int, string)
-{
- buf := array[128] of byte;
- if((n := readstrnl(fd, buf, len buf)) < 0)
- return (-1, -1, sys->sprint("error reading version: %r"));
- # id string is "SSH-m.n-comment". We need m=1, n>=5.
- s := string buf[0: n];
- (nf, fld) := sys->tokenize(s, "-\r\n");
- if(nf < 3 || hd fld != "SSH")
- return (-1, -1, sys->sprint("unexpected protocol reply: %s", s));
- (nf, fld) = sys->tokenize(hd tl fld, ".");
- if(nf < 2)
- return (-1, -1, "invalid SSH version string in "+s);
- return (1, int hd tl fld, s);
-}
-
-calcsessid(hostmod: ref IPint, servermod: ref IPint, cookie: array of byte): array of byte
-{
- b1 := hostmod.iptobebytes();
- b2 := servermod.iptobebytes();
- buf := array[len b1+len b2+COOKIELEN] of byte;
- buf[0:] = b1;
- buf[len b1:] = b2;
- buf[len b1+len b2:] = cookie[0: COOKIELEN];
- sessid := array[Crypt->MD5dlen] of byte;
- crypt->md5(buf, len buf, sessid, nil);
- return sessid;
-}
-
-Msg.text(m: self ref Msg): string
-{
- if(0 <= m.mtype && m.mtype < len msgnames)
- return msgnames[m.mtype];
- return sys->sprint("<unknown type %d>", m.mtype);
-}
-
-Msg.fulltext(m: self ref Msg): string
-{
- s := m.text();
- n := m.ep;
- if(n > 64)
- n = 64;
- for(i := 0; i < n; i++)
- s += sys->sprint(" %.2ux", int m.data[i]);
- if(n != m.ep)
- s += " ...";
- return s;
-}
-
-badmsg(m: ref Msg, want: int, errmsg: string)
-{
- if(m == nil)
- s := sys->sprint("<early eof: %s>", errmsg);
- else
- s = m.text();
- if(want)
- error(sys->sprint("got %s message expecting %s", s, msgnames[want]));
- error(sys->sprint("got unexpected %s message", s));
-}
-
-Msg.mk(mtype: int, length: int): ref Msg
-{
- if(length > 256*1024)
- raise "message too large";
- return ref Msg(mtype, array[4+8+1+length+4] of byte, 0, 0, length);
-}
-
-# used by auth tis
-unrecvmsg(c: ref Conn, m: ref Msg)
-{
- debug(DBG_PROTO, sys->sprint("unreceived %s len %d\n", msgnames[m.mtype], m.ep-m.rp));
- c.unget = m;
-}
-
-readmsg(c: ref Conn, fd: ref Sys->FD): ref Msg
-{
- if(c.unget != nil){ # TO DO: assumes state of processes ensures exclusive access
- m := c.unget;
- c.unget = nil;
- return m;
- }
- buf := array[4] of byte;
- if((n := sys->readn(fd, buf, len buf)) != len buf){
- if(n < 0)
- sys->werrstr("short net read: %r");
- else
- sys->werrstr("short net read");
- return nil;
- }
- length := get4(buf, 0);
- if(length < 5 || length > 256*1024){
- sys->werrstr(sys->sprint("implausible packet length: %.8ux", length));
- return nil;
- }
- pad := 8-length%8;
- m := ref Msg(0, array[pad+length] of byte, pad, 0, pad+length-4);
- if(sys->readn(fd, m.data, len m.data) != len m.data){
- sys->werrstr(sys->sprint("short net read: %r"));
- return nil;
- }
- if(c.cipher != nil)
- c.cipher->decrypt(m.data, length+pad);
- crc := sum32(0, m.data, m.ep);
- crc0 := get4(m.data, m.ep);
- if(crc != crc0){
- sys->werrstr(sys->sprint("bad crc %#ux != %#ux (packet length %ud)", crc, crc0, length));
- return nil;
- }
- m.mtype = int m.data[m.rp++];
- return m;
-}
-
-recvmsg(c: ref Conn, mtype: int): ref Msg
-{
- (m, errmsg) := <-c.in;
- if(mtype == 0){
- # no checking
- }else if(mtype == -1){
- # must not be nil
- if(m == nil)
- error(Ehangup);
- }else if(m == nil || m.mtype != mtype) # must be given type
- badmsg(m, mtype, errmsg);
- return m;
-}
-
-writemsg(c: ref Conn, m: ref Msg, fd: ref Sys->FD): int
-{
- datalen := m.wp;
- length := datalen+1+4; # will add type and crc
- pad := 8-length%8;
- debug(DBG_PROTO, sys->sprint("->[%d] %s\n", datalen, m.fulltext()));
- m.data[4+pad+1:] = m.data[0: datalen]; # slide data to correct position (is this guaranteed?) TO DO
- put4(m.data, 0, length);
- p := 4;
- if(c.cipher != nil)
- for(i := 0; i < pad; i++)
- m.data[p++] = byte fastrand();
- else{
- for(i = 0; i < pad; i++)
- m.data[p++] = byte 0;
- }
- m.data[p++] = byte m.mtype;
- # data already in position
- p += datalen;
- crc := sum32(0, m.data[4:], pad+1+datalen);
- put4(m.data, p, crc);
- p += 4;
- if(c.cipher != nil)
- c.cipher->encrypt(m.data[4:], length+pad);
- if(sys->write(fd, m.data, p) != p)
- return -1;
- return 0;
-}
-
-Msg.get1(m: self ref Msg): int
-{
- if(m.rp >= m.ep)
- raise Edecode;
- return int m.data[m.rp++];
-}
-
-Msg.get2(m: self ref Msg): int
-{
- if(m.rp+2 > m.ep)
- raise Edecode;
- x := (int m.data[m.rp+0]<<8) | int m.data[m.rp+1];
- m.rp += 2;
- return x;
-}
-
-Msg.get4(m: self ref Msg): int
-{
- if(m.rp+4 > m.ep)
- raise Edecode;
- x := int m.data[m.rp+0]<<24|int m.data[m.rp+1]<<16|int m.data[m.rp+2]<<8|int m.data[m.rp+3];
- m.rp += 4;
- return x;
-}
-
-Msg.getarray(m: self ref Msg): array of byte
-{
- length := m.get4();
- if(m.rp+length > m.ep)
- raise Edecode;
- p := m.data[m.rp: m.rp+length];
- m.rp += length;
- return p;
-}
-
-Msg.getstring(m: self ref Msg): string
-{
- return string m.getarray();
-}
-
-Msg.getbytes(m: self ref Msg, n: int): array of byte
-{
- if(m.rp+n > m.ep)
- raise Edecode;
- p := m.data[m.rp: m.rp+n];
- m.rp += n;
- return p;
-}
-
-Msg.getipint(m: self ref Msg): ref IPint
-{
- n := (m.get2()+7)/8; # get2 returns # bits
- return IPint.bebytestoip(m.getbytes(n));
-}
-
-Msg.getpk(m: self ref Msg): ref PK.RSA
-{
- m.get4();
- ek := m.getipint();
- n := m.getipint();
- return ref PK.RSA(n, ek);
-}
-
-Msg.put1(m: self ref Msg, x: int)
-{
- if(m.wp >= m.ep)
- raise Eencode;
- m.data[m.wp++] = byte x;
-}
-
-Msg.put2(m: self ref Msg, x: int)
-{
- if(m.wp+2 > m.ep)
- raise Eencode;
- (m.data[m.wp+0], m.data[m.wp+1]) = (byte (x>>8), byte x);
- m.wp += 2;
-}
-
-Msg.put4(m: self ref Msg, x: int)
-{
- if(m.wp+4 > m.ep)
- raise Eencode;
- (m.data[m.wp+0], m.data[m.wp+1], m.data[m.wp+2], m.data[m.wp+3]) = (byte (x>>24), byte (x>>16), byte (x>>8), byte x);
- m.wp += 4;
-}
-
-Msg.putstring(m: self ref Msg, s: string)
-{
- b := array of byte s;
- m.put4(len b);
- m.putbytes(b, len b);
-}
-
-Msg.putbytes(m: self ref Msg, a: array of byte, n: int)
-{
- if(m.wp+n > m.ep)
- raise Eencode;
- m.data[m.wp:] = a[0: n];
- m.wp += n;
-}
-
-Msg.putipint(m: self ref Msg, b: ref IPint)
-{
- bits := b.bits();
- m.put2(bits);
-# n := (bits+7)/8;
- ba := b.iptobebytes();
- n := len ba;
- if(m.wp+n > m.ep)
- raise Eencode;
- m.data[m.wp:] = ba;
- m.wp += n;
-}
-
-Msg.putpk(m: self ref Msg, key: ref PK.RSA)
-{
- m.put4(key.n.bits());
- m.putipint(key.ek);
- m.putipint(key.n);
-}
-
-crctab := array[256] of int;
-
-initsum32()
-{
- poly := int 16redb88320;
- for(i := 0; i < 256; i++){
- crc := i;
- for(j := 0; j < 8; j++)
- if(crc&1)
- crc = ((crc>>1) & int ~16r80000000)^poly; # need unsigned shift
- else
- crc = (crc>>1) & int ~16r80000000;
- crctab[i] = crc;
- }
-}
-
-first_38: int = 1;
-
-sum32(lcrc: int, buf: array of byte, n: int): int
-{
- crc := lcrc;
- if(first_38){
- first_38 = 0;
- initsum32();
- }
- s := 0;
- while(n-- > 0)
- crc = crctab[(crc^int buf[s++])&16rff]^((crc>>8)&int ~16rFF000000);
- return crc;
-}
-
-erase(b: array of byte)
-{
- for(i := 0; i < len b; i++)
- b[i] = byte 0;
-}
-
-#
-# PKCS#1 padding
-#
-rsapad(b: ref IPint, n: int): ref IPint
-{
- a := b.iptobebytes();
- pad := n - len a - 3;
- if(pad < 0)
- error("value too large to pad"); # can't happen if keys are required size
- buf := array[n] of byte;
- buf[0] = byte 0;
- buf[1] = byte 2;
- for(i := 2; --pad >= 0; i++)
- buf[i] = byte (1+fastrand()%255);
- buf[i++] = byte 0;
- buf[i:] = a;
- c := IPint.bebytestoip(buf);
- erase(buf);
- erase(a);
- return c;
-}
-
-rsaunpad(b: ref IPint): ref IPint
-{
- buf := b.iptobebytes();
- i := 0;
- if(buf[0] == byte 0)
- i++;
- if(buf[i] != byte 2)
- error("bad data in rsaunpad");
- for(; i < len buf; i++)
- if(buf[i] == byte 0)
- break;
- c := IPint.bebytestoip(buf[i:]);
- erase(buf);
- return c;
-}
-
-rsaencryptbuf(key: ref PK.RSA, buf: array of byte, nbuf: int): ref IPint
-{
- n := (key.n.bits()+7)/8;
- a := IPint.bebytestoip(buf[0: nbuf]);
- b := rsapad(a, n);
- return crypt->rsaencrypt(key, b);
-}
-
-iptorjustbe(b: ref IPint, buf: array of byte, length: int)
-{
- a := b.iptobebytes();
- if(len a < length){
- length -= len a;
- erase(buf[0: length]);
- buf[length:] = a;
- }else
- buf[0:] = a[0: length];
- erase(a);
-}
-
-hex(a: array of byte): string
-{
- s := "";
- for(i := 0; i < len a; i++)
- s += sys->sprint("%.2ux", int a[i]);
- return s;
-}
-
-debug(n: int, s: string)
-{
- sys->fprint(sys->fildes(2), "debug: %s", s);
-}
-
-error(s: string)
-{
- sys->fprint(sys->fildes(2), "error: %s\n", s);
- raise "error";
-}
-
-rsagen(bits: int): ref SK.RSA
-{
- return crypt->rsagen(bits, 6, 0);
-}
-
-rsaencrypt(key: ref PK.RSA, b: ref IPint): ref IPint
-{
- return crypt->rsaencrypt(key, b);
-}
-
-rsadecrypt(key: ref SK.RSA, b: ref IPint): ref IPint
-{
- return crypt->rsadecrypt(key, b);
-}
-
-fastrand(): int
-{
- return int rand->bigrand(4294967295);
-}
-
-readstrnl(fd: ref Sys->FD, buf: array of byte, nbuf: int): int
-{
- for(i := 0; i < nbuf; i++)
- case sys->read(fd, buf[i:], 1) {
- -1 =>
- return -1;
- 0 =>
- sys->werrstr("unexpected EOF");
- return -1;
- * =>
- if(buf[i] == byte '\n')
- return i;
- }
- sys->werrstr("line too long");
- return -1;
-}
-
-eqbytes(a: array of byte, b: array of byte, n: int): int
-{
- if(len a > n || len b > n)
- return 0;
- for(i := 0; i < n; i++)
- if(a[i] != b[i])
- return 0;
- return 1;
-}
-
-get4(a: array of byte, o: int): int
-{
- return int a[o+0]<<24 | int a[o+1]<<16 | int a[o+2]<<8 | int a[o+3];
-}
-
-put4(a: array of byte, o: int, v: int)
-{
- a[o+0] = byte (v>>24);
- a[o+1] = byte (v>>16);
- a[o+2] = byte (v>>8);
- a[o+3] = byte v;
-}
diff --git a/appl/cmd/ssh/sshio.m b/appl/cmd/ssh/sshio.m
deleted file mode 100644
index 6c186e63..00000000
--- a/appl/cmd/ssh/sshio.m
+++ /dev/null
@@ -1,194 +0,0 @@
-
- # internal debugging flags
- DBG, DBG_CRYPTO, DBG_PACKET, DBG_AUTH, DBG_PROC, DBG_PROTO, DBG_IO, DBG_SCP: con 1<<iota;
-
- # protocol packet types
- SSH_MSG_NONE, # 0
- SSH_MSG_DISCONNECT,
- SSH_SMSG_PUBLIC_KEY,
- SSH_CMSG_SESSION_KEY,
- SSH_CMSG_USER,
- SSH_CMSG_AUTH_RHOSTS,
- SSH_CMSG_AUTH_RSA,
- SSH_SMSG_AUTH_RSA_CHALLENGE,
- SSH_CMSG_AUTH_RSA_RESPONSE,
- SSH_CMSG_AUTH_PASSWORD, # 10
- SSH_CMSG_REQUEST_PTY,
- SSH_CMSG_WINDOW_SIZE,
- SSH_CMSG_EXEC_SHELL,
- SSH_CMSG_EXEC_CMD,
- SSH_SMSG_SUCCESS,
- SSH_SMSG_FAILURE,
- SSH_CMSG_STDIN_DATA,
- SSH_SMSG_STDOUT_DATA,
- SSH_SMSG_STDERR_DATA,
- SSH_CMSG_EOF, # 20
- SSH_SMSG_EXITSTATUS,
- SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
- SSH_MSG_CHANNEL_OPEN_FAILURE,
- SSH_MSG_CHANNEL_DATA,
- SSH_MSG_CHANNEL_INPUT_EOF,
- SSH_MSG_CHANNEL_OUTPUT_CLOSED,
- SSH_MSG_UNIX_DOMAIN_X11_FORWARDING, # obsolete
- SSH_SMSG_X11_OPEN,
- SSH_CMSG_PORT_FORWARD_REQUEST,
- SSH_MSG_PORT_OPEN, # 30
- SSH_CMSG_AGENT_REQUEST_FORWARDING,
- SSH_SMSG_AGENT_OPEN,
- SSH_MSG_IGNORE,
- SSH_CMSG_EXIT_CONFIRMATION,
- SSH_CMSG_X11_REQUEST_FORWARDING,
- SSH_CMSG_AUTH_RHOSTS_RSA,
- SSH_MSG_DEBUG,
- SSH_CMSG_REQUEST_COMPRESSION,
- SSH_CMSG_MAX_PACKET_SIZE,
- SSH_CMSG_AUTH_TIS, # 40
- SSH_SMSG_AUTH_TIS_CHALLENGE,
- SSH_CMSG_AUTH_TIS_RESPONSE,
- SSH_CMSG_AUTH_KERBEROS,
- SSH_SMSG_AUTH_KERBEROS_RESPONSE,
- SSH_CMSG_HAVE_KERBEROS_TGT: con iota;
-
- SSH_MSG_ERROR: con -1;
-
- # protocol flags
- SSH_PROTOFLAG_SCREEN_NUMBER: con 1<<0;
- SSH_PROTOFLAG_HOST_IN_FWD_OPEN: con 1<<1;
-
- # agent protocol packet types
- SSH_AGENTC_NONE,
- SSH_AGENTC_REQUEST_RSA_IDENTITIES,
- SSH_AGENT_RSA_IDENTITIES_ANSWER,
- SSH_AGENTC_RSA_CHALLENGE,
- SSH_AGENT_RSA_RESPONSE,
- SSH_AGENT_FAILURE,
- SSH_AGENT_SUCCESS,
- SSH_AGENTC_ADD_RSA_IDENTITY,
- SSH_AGENTC_REMOVE_RSA_IDENTITY: con iota;
-
- # protocol constants
- SSH_MAX_DATA: con 256*1024;
- SSH_MAX_MSG: con SSH_MAX_DATA+4;
- SESSKEYLEN: con 32;
- SESSIDLEN: con 16;
- COOKIELEN: con 8;
-
- # crypto ids
- SSH_CIPHER_NONE,
- SSH_CIPHER_IDEA,
- SSH_CIPHER_DES,
- SSH_CIPHER_3DES,
- SSH_CIPHER_TSS,
- SSH_CIPHER_RC4,
- SSH_CIPHER_BLOWFISH: con iota;
-
- # auth method ids
- SSH_AUTH_RHOSTS,
- SSH_AUTH_RSA,
- SSH_AUTH_PASSWORD,
- SSH_AUTH_RHOSTS_RSA,
- SSH_AUTH_TIS,
- SSH_AUTH_USER_RSA: con 1+iota;
-
-Edecode: con "error decoding input packet";
-Eencode: con "out of space encoding output packet (BUG)";
-Ehangup: con "hungup connection";
-Ememory: con "out of memory";
-
-Cipher: module
-{
- id: fn(): int;
- init: fn(key: array of byte, isserver: int);
- encrypt: fn(a: array of byte, n: int);
- decrypt: fn(a: array of byte, n: int);
-};
-
-Auth: module
-{
- AuthInfo: adt{
- user: string;
- cap: string;
- };
-
- id: fn(): int;
- firstmsg: fn(): int;
- init: fn(nil: Sshio);
- authsrv: fn(nil: ref Sshio->Conn, nil: ref Sshio->Msg): ref AuthInfo;
- auth: fn(nil: ref Sshio->Conn): int;
-};
-
-Sshio: module
-{
- PATH: con "sshio.dis";
-
- Conn: adt{
- in: chan of (ref Msg, string);
- out: chan of ref Msg;
-
- sessid: array of byte;
- sesskey: array of byte;
- hostkey: ref Crypt->PK.RSA;
- flags: int;
- cipher: Cipher; # chosen cipher
- user: string;
- host: string;
- interactive: int;
- unget: ref Msg;
-
- mk: fn(host: string, fd: ref Sys->FD): ref Conn;
- setkey: fn(c: self ref Conn, key: ref Crypt->PK.RSA);
- };
-
- Msg: adt{
- mtype: int;
- data: array of byte;
- rp: int; # read pointer
- wp: int; # write pointer
- ep: int; # byte just beyond message data
-
- mk: fn(mtype: int, length: int): ref Msg;
- text: fn(m: self ref Msg): string;
- fulltext: fn(m: self ref Msg): string;
-
- get1: fn(m: self ref Msg): int;
- get2: fn(m: self ref Msg): int;
- get4: fn(m: self ref Msg): int;
- getstring: fn(m: self ref Msg): string;
- getbytes: fn(m: self ref Msg, n: int): array of byte;
- getarray: fn(m: self ref Msg): array of byte;
- getipint: fn(m: self ref Msg): ref IPints->IPint;
- getpk: fn(m: self ref Msg): ref Crypt->PK.RSA;
-
- put1: fn(m: self ref Msg, nil: int);
- put2: fn(m: self ref Msg, nil: int);
- put4: fn(m: self ref Msg, nil: int);
- putstring: fn(m: self ref Msg, s: string);
- putbytes: fn(m: self ref Msg, a: array of byte, n: int);
- putipint: fn(m: self ref Msg, mp: ref IPints->IPint);
- putpk: fn(m: self ref Msg, pk: ref Crypt->PK.RSA);
- };
-
- init: fn();
-
- badmsg: fn(nil: ref Msg, nil: int, err: string);
- recvmsg: fn(nil: ref Conn, nil: int): ref Msg;
- unrecvmsg: fn(nil: ref Conn, nil: ref Msg);
- rsapad: fn(nil: ref IPints->IPint, nil: int): ref IPints->IPint;
- rsaunpad: fn(nil: ref IPints->IPint): ref IPints->IPint;
- iptorjustbe: fn(nil: ref IPints->IPint, nil: array of byte, nil: int);
- rsaencryptbuf: fn(nil: ref Crypt->PK.RSA, nil: array of byte, nil: int): ref IPints->IPint;
- rsagen: fn(nbits: int): ref Crypt->SK.RSA;
- rsaencrypt: fn(key: ref Crypt->PK.RSA, b: ref IPints->IPint): ref IPints->IPint;
- rsadecrypt: fn(key: ref Crypt->SK.RSA, b: ref IPints->IPint): ref IPints->IPint;
-
- debug: fn(nil: int, nil: string);
- error: fn(nil: string);
- readstrnl: fn(fd: ref Sys->FD, buf: array of byte, nbytes: int): int;
- calcsessid: fn(hostmod: ref IPints->IPint, servermod: ref IPints->IPint, cookie: array of byte): array of byte;
-# sshlog: fn(nil: array of byte); # TBA was ...
-
- fastrand: fn(): int;
- eqbytes: fn(a: array of byte, b: array of byte, n: int): int;
- readversion: fn(fd: ref Sys->FD): (int, int, string);
- hex: fn(a: array of byte): string;
-};
diff --git a/appl/cmd/ssh/sshserve.b b/appl/cmd/ssh/sshserve.b
deleted file mode 100644
index dc8bbd31..00000000
--- a/appl/cmd/ssh/sshserve.b
+++ /dev/null
@@ -1,495 +0,0 @@
-implement Sshserve;
-
-include "sys.m";
- sys: Sys;
-
-include "draw.m";
-
-include "ipints.m";
- ipints: IPints;
- IPint: import ipints;
-
-include "crypt.m";
- crypt: Crypt;
- PK, SK: import crypt;
-
-include "env.m";
- env: Env;
-
-include "sh.m";
- sh: Sh;
-
-include "wait.m";
- wait: Wait;
-
-include "arg.m";
-
-include "sshio.m";
- sshio: Sshio;
- Conn, Msg: import sshio;
- recvmsg: import sshio;
- error, debug: import sshio;
-
-Sshserve: module
-{
- init: fn(nil: ref Draw->Context, argl: list of string);
-};
-
-AuthRpc: adt {};
-debuglevel := 0;
-
-cipherlist := "blowfish rc4 3des";
-ciphers: list of Cipher;
-
-authlist := "rsa password tis";
-authsrvs: list of Auth;
-
-maxmsg := 256*1024;
-
-serverpriv: ref SK.RSA;
-serverkey: ref PK.RSA;
-hostpriv: ref SK.RSA;
-
-init(nil: ref Draw->Context, args: list of string)
-{
- sys = load Sys Sys->PATH;
- ipints = load IPints IPints->PATH;
- crypt = load Crypt Crypt->PATH;
- env = load Env Env->PATH;
- sh = load Sh Sh->PATH;
- sshio = load Sshio Sshio->PATH;
- sshio->init();
- wait = load Wait Wait->PATH;
- wait->init();
-# fmtinstall('B', mpfmt);
-# fmtinstall('H', encodefmt);
- sys->pctl(Sys->NEWPGRP|Sys->FORKFD|Sys->FORKNS|Sys->FORKENV, nil);
- keyfile: string;
- arg := load Arg Arg->PATH;
- arg->setusage("sshserve [-A authlist] [-c cipherlist] [-k keyfile] client-ip-address");
- arg->init(args);
- while((o := arg->opt()) != 0){
- case o {
- 'D' =>
- debuglevel = int arg->earg();
- 'A' =>
- authlist = arg->earg();
- 'c' =>
- cipherlist = arg->earg();
- 'k' =>
- keyfile = arg->earg();
- * =>
- arg->usage();
- }
- }
- args = arg->argv();
- if(len args != 1)
- arg->usage();
- arg = nil;
-
- sys->dup(2, 1);
-# if(keyfile != nil)
-# ; # read hostpriv from file
-# sshlog("connect from %s", c.host);
- authsrvs = loadlist("auth", authlist, authload);
- ciphers = loadlist("cipher", cipherlist, cipherload);
- hostpriv = crypt->rsagen(1024, 6, 0);
- serverpriv = crypt->rsagen(768, 6, 0);
- serverkey = serverpriv.pk;
- {
- versioning(sys->fildes(0));
- c := Conn.mk(hd args, sys->fildes(0));
- c.setkey(hostpriv.pk);
- authenticate(c);
- comms(c);
- }exception e{
- "fail:*" =>
- raise e;
- "error*" =>
- notegrp(sys->pctl(0, nil), "error");
- raise "fail:"+e;
- }
-}
-
-authload(f: string): Auth
-{
- return load Auth f;
-}
-
-cipherload(f: string): Cipher
-{
- return load Cipher f;
-}
-
-loadlist[T](sort: string, set: string, loadf: ref fn(f: string): T): list of T
-{
- l: list of T;
- (nil, fld) := sys->tokenize(set, " \t,");
- for(; fld != nil; fld = tl fld){
- f := "/dis/ssh/"+sort+hd fld+".dis";
- m := loadf(f);
- if(m == nil)
- error(sys->sprint("unknown %s scheme %s (%s)", sort, hd fld, f));
- l = m :: l;
- }
- return l;
-}
-
-comms(c: ref Conn)
-{
- (kidpid, infd, waiting) := prelude(c);
-Work:
- for(;;)alt{
- (m, nil) := <-c.in =>
- if(m == nil){
- notegrp(kidpid, "hungup");
- exit;
- }
- case m.mtype {
- * =>
- sshio->badmsg(m, 0, nil);
- SSH_MSG_DISCONNECT =>
- notegrp(kidpid, "hungup");
- sysfatal("client disconnected");
- SSH_CMSG_STDIN_DATA =>
- if(infd != nil){
- n := m.get4();
- sys->write(infd, m.getbytes(n), n);
- }
- SSH_CMSG_EOF =>
- infd = nil;
- SSH_CMSG_EXIT_CONFIRMATION =>
- # sent by some clients as dying breath
- notegrp(kidpid, "hungup");
- break Work;
- SSH_CMSG_WINDOW_SIZE =>
- ; # we don't care
- }
- (pid, nil, status) := <-waiting =>
- if(pid == kidpid){
- if(status != "" && status != "0"){
- m := Msg.mk(SSH_MSG_DISCONNECT, 4+Sys->UTFmax*len status);
- m.putstring(status);
- sendmsg(c, m);
- }else{
- m := Msg.mk(SSH_SMSG_EXITSTATUS, 4);
- m.put4(0);
- sendmsg(c, m);
- }
- sendmsg(c, nil);
- break Work;
- }
- }
- notegrp(sys->pctl(0, nil), "done");
-}
-
-prelude(c: ref Conn): (int, ref Sys->FD, chan of (int, string, string))
-{
- for(;;){
- m := recvmsg(c, -1);
- if(m == nil)
- return (-1, nil, nil);
- case m.mtype {
- * =>
- sendmsg(c, Msg.mk(SSH_SMSG_FAILURE, 0));
- SSH_MSG_DISCONNECT =>
- sysfatal("client disconnected");
- SSH_CMSG_REQUEST_PTY =>
- sendmsg(c, Msg.mk(SSH_SMSG_SUCCESS, 0));
- SSH_CMSG_MAX_PACKET_SIZE =>
- n := m.get4();
- if(n >= 32 && n <= SSH_MAX_MSG){
- maxmsg = n;
- sendmsg(c, Msg.mk(SSH_SMSG_SUCCESS, 0));
- }else
- sendmsg(c, Msg.mk(SSH_SMSG_FAILURE, 0));
- SSH_CMSG_EXEC_SHELL =>
- return startcmd(c, nil);
- SSH_CMSG_EXEC_CMD =>
- cmd := m.getstring();
- return startcmd(c, cmd);
- }
- }
-}
-
-copyout(c: ref Conn, fd: ref Sys->FD, mtype: int)
-{
- buf := array[8192] of byte;
- max := len buf;
- if(max > maxmsg-32) # 32 is an overestimate of packet overhead
- max = maxmsg-32;
- if(max <= 0)
- sysfatal("maximum message size too small");
- while((n := sys->read(fd, buf, max)) > 0){
- m := Msg.mk(mtype, 4+n);
- m.put4(n);
- m.putbytes(buf, n);
- sendmsg(c, m);
- }
-}
-
-send_ssh_smsg_public_key(c: ref Conn, cookie: array of byte)
-{
- m := Msg.mk(SSH_SMSG_PUBLIC_KEY, 2048);
- m.putbytes(cookie, COOKIELEN);
- m.putpk(serverkey);
- m.putpk(c.hostkey);
- m.put4(c.flags);
- ciphermask := 0;
- for(l1 := ciphers; l1 != nil; l1 = tl l1)
- ciphermask |= 1<<(hd l1)->id();
- m.put4(ciphermask);
- authmask := 0;
- for(l2 := authsrvs; l2 != nil; l2 = tl l2)
- authmask |= 1<<(hd l2)->id();
- m.put4(authmask);
- sendmsg(c, m);
-}
-
-rpcdecrypt(rpc: ref AuthRpc, b: ref IPint): ref IPint
-{
- raise "rpcdecrypt";
-# p := array of byte b.iptostr(16);
-# if(auth_rpc(rpc, "write", p, len p) != ARok)
-# sysfatal("factotum rsa write: %r");
-# if(auth_rpc(rpc, "read", nil, 0) != ARok)
-# sysfatal("factotum rsa read: %r");
-# return strtomp(rpc.arg, nil, 16, nil);
-}
-
-recv_ssh_cmsg_session_key(c: ref Conn, rpc: ref AuthRpc, cookie: array of byte)
-{
- m := recvmsg(c, SSH_CMSG_SESSION_KEY);
- id := m.get1();
- c.cipher = nil;
- for(l := ciphers; l != nil; l = tl l)
- if((hd l)->id() == id){
- c.cipher = hd l;
- break;
- }
- if(c.cipher == nil)
- sysfatal(sys->sprint("invalid cipher %d selected", id));
- if(!sshio->eqbytes(m.getbytes(COOKIELEN), cookie, len cookie))
- sysfatal("bad cookie");
- serverkeylen := serverkey.n.bits();
- hostkeylen := c.hostkey.n.bits();
- ksmall, kbig: ref SK.RSA;
- if(serverkeylen+128 <= hostkeylen){
- ksmall = serverpriv;
- kbig = nil;
- }else if(hostkeylen+128 <= serverkeylen){
- ksmall = nil;
- kbig = serverpriv;
- }else
- sysfatal("server session and host keys do not differ by at least 128 bits");
- b := m.getipint();
- debug(DBG_CRYPTO, sys->sprint("encrypted with kbig is %s\n", b.iptostr(16)));
- if(kbig != nil)
- b = sshio->rsadecrypt(kbig, b);
- else
-# b = rpcdecrypt(rpc, b);
- b = sshio->rsadecrypt(hostpriv, b);
- b = sshio->rsaunpad(b);
- sshio->debug(DBG_CRYPTO, sys->sprint("encrypted with ksmall is %s\n", b.iptostr(16)));
- if(ksmall != nil)
- b = sshio->rsadecrypt(ksmall, b);
- else
-# b = rpcdecrypt(rpc, b);
- b = sshio->rsadecrypt(hostpriv, b);
- b = sshio->rsaunpad(b);
- debug(DBG_CRYPTO, sys->sprint("munged is %s\n", b.iptostr(16)));
- n := (b.bits()+7)/8;
- if(n < SESSKEYLEN)
- sysfatal("client sent short session key");
- buf := array[SESSKEYLEN] of byte;
- sshio->iptorjustbe(b, buf, SESSKEYLEN);
- for(i := 0; i < SESSIDLEN; i++)
- buf[i] ^= c.sessid[i];
- c.sesskey[0: ] = buf[0: SESSKEYLEN];
- debug(DBG_CRYPTO, sys->sprint("unmunged is %.*s\n", SESSKEYLEN*2, sshio->hex(buf)));
- c.flags = m.get4();
-}
-
-authsrvuser(c: ref Conn)
-{
- m := recvmsg(c, SSH_CMSG_USER);
- user := m.getstring();
- c.user = user;
- inited := 0;
- ai: ref Auth->AuthInfo;
- while(authsrvs != nil && ai == nil){
-# #
-# # * clumsy: if the client aborted the auth_tis early
-# # * we don't send a new failure. we check this by
-# # * looking at c->unget, which is only used in that
-# # * case.
-# #
- if(c.unget == nil)
- sendmsg(c, Msg.mk(SSH_SMSG_FAILURE, 0));
- m = recvmsg(c, -1);
- for(l := authsrvs; l != nil; l = tl l)
- if((hd l)->firstmsg() == m.mtype){
- bit := 1 << (hd l)->id();
- if((inited & bit) == 0){
- (hd l)->init(sshio);
- inited |= bit;
- }
- ai = (hd l)->authsrv(c, m);
- break;
- }
- if(l == nil)
- sshio->badmsg(m, 0, nil);
- }
- sendmsg(c, Msg.mk(SSH_SMSG_SUCCESS, 0));
-# if(noworld(ai.cuid))
-# ns := "/lib/namespace.noworld";
-# else
-# ns = nil;
-# if(auth_chuid(ai, ns) < 0){
-# sshlog("auth_chuid to %s: %r", ai.cuid);
-# sysfatal("auth_chuid: %r");
-# }
-# sshlog("logged in as %q", ai.user);
- if(ai != nil)
- sys->print("logged in as %q\n", ai.user);
-}
-
-keyjunk()
-{
- p: array of byte;
- m: ref IPint;
- rpc: ref AuthRpc;
- key: ref PK.RSA;
-
-# #
-# # BUG: should use `attr' to get the key attributes
-# # after the read, but that's not implemented yet.
-# #
-# if((b = Bopen("/mnt/factotum/ctl", OREAD)) == nil)
-# sysfatal("open /mnt/factotum/ctl: %r");
-# while((p = Brdline(b, '\n')) != nil){
-# if(strstr(p, " proto=rsa ") != nil && strstr(p, " service=sshserve ") != nil)
-# break;
-# }
-# if(p == nil)
-# sysfatal("no sshserve keys found in /mnt/factotum/ctl");
-# a = _parseattr(p);
-# Bterm(b);
-# key = rsaprivalloc();
-# if((p = _strfindattr(a, "n")) == nil)
-# sysfatal("no n in sshserve key");
-# if((key.n = IPint.strtoip(p, 16)) == nil)
-# sysfatal("bad n in sshserve key");
-# if((p = _strfindattr(a, "ek")) == nil)
-# sysfatal("no ek in sshserve key");
-# if((key.ek = IPint.strtoip(p, 16)) == nil)
-# sysfatal("bad ek in sshserve key");
-# _freeattr(a);
-# if((afd = sys->open("/mnt/factotum/rpc", ORDWR)) == nil)
-# sysfatal("open /mnt/factotum/rpc: %r");
-# if((rpc = auth_allocrpc(afd)) == nil)
-# sysfatal("auth_allocrpc: %r");
-# p = "proto=rsa role=client service=sshserve";
-# if(auth_rpc(rpc, "start", p, len p) != ARok)
-# sysfatal("auth_rpc start %s: %r", p);
-# if(auth_rpc(rpc, "read", nil, 0) != ARok)
-# sysfatal("auth_rpc read: %r");
-# m = strtomp(rpc.arg, nil, 16, nil);
-# if(mpcmp(m, key.n) != 0)
-# sysfatal("key in /mnt/factotum/ctl does not match rpc key");
-# mpfree(m);
-# c.hostkey = key;
-}
-
-versioning(fd: ref Sys->FD)
-{
- sys->fprint(fd, "SSH-1.5-Inferno\n");
- (maj, min, err_or_id) := sshio->readversion(fd);
- if(maj < 0)
- sysfatal(err_or_id);
- if(maj != 1 || min < 5)
- sysfatal(sys->sprint("protocol mismatch; got %s, need SSH-1.x for x >= 5", err_or_id));
-}
-
-authenticate(c: ref Conn)
-{
- rpc: ref AuthRpc;
-
- cookie := array[COOKIELEN] of {* => byte sshio->fastrand()};
- c.sessid = sshio->calcsessid(c.hostkey.n, serverkey.n, cookie);
- send_ssh_smsg_public_key(c, cookie);
- recv_ssh_cmsg_session_key(c, rpc, cookie);
-# afd = nil;
- c.cipher->init(c.sesskey, 1); # turns on encryption
- sendmsg(c, Msg.mk(SSH_SMSG_SUCCESS, 0));
- authsrvuser(c);
-}
-
-startcmd(c: ref Conn, cmd: string): (int, ref Sys->FD, chan of (int, string, string))
-{
- pfd := array[3] of {* => array[2] of ref Sys->FD};
- for(i := 0; i < 3; i++)
- if(sys->pipe(pfd[i]) < 0)
- sysfatal(sys->sprint("pipe: %r"));
- wfd := sys->open("#p/"+string sys->pctl(0, nil)+"/wait", Sys->OREAD);
- if(wfd == nil)
- sysfatal(sys->sprint("open wait: %r"));
- pidc := chan of int;
- spawn startcmd1(c, cmd, pfd, pidc);
- kidpid := <-pidc;
- (nil, waited) := wait->monitor(wfd);
- spawn copyout(c, pfd[1][0], SSH_SMSG_STDOUT_DATA);
- pfd[1][0] = nil;
- spawn copyout(c, pfd[2][0], SSH_SMSG_STDERR_DATA);
- pfd[2][0] = nil;
- return (kidpid, pfd[0][0], waited);
-}
-
-startcmd1(c: ref Conn, cmd: string, pfd: array of array of ref Sys->FD, pidc: chan of int)
-{
- sysname := env->getenv("sysname");
- tz := env->getenv("timezone");
- sys->pctl(Sys->FORKFD, nil);
- for(i := 0; i < len pfd; i++)
- if(sys->dup(pfd[i][1].fd, i) < 0)
- sysfatal(sys->sprint("dup: %r"));
- pfd = nil;
- sys->pctl(Sys->NEWPGRP|Sys->FORKNS|Sys->FORKENV|Sys->NEWFD, 0::1::2::nil);
- pidc <-= sys->pctl(0, nil);
- env->setenv("user", c.user);
- if(sysname != nil)
- env->setenv("sysname", sysname);
- if(tz != nil)
- env->setenv("tz", tz);
- if(sys->chdir("/usr/"+c.user) < 0)
- sys->chdir("/");
- if(cmd != nil){
- env->setenv("service", "rx");
- status := sh->run(nil, list of {"/dis/sh.dis", "-lc", cmd});
- if(status != nil)
- raise "fail:"+status;
- }else{
- env->setenv("service", "con");
- #execl("/bin/ip/telnetd", "telnetd", "-tn", nil); # TO DO: just for echo and line editing
- sys->fprint(sys->fildes(2), "sshserve: cannot run /dis/ip/telnetd: %r");
- }
-}
-
-sysfatal(s: string)
-{
- sys->print("sysfatal: %s\n", s);
- notegrp(sys->pctl(0, nil), "zap");
- exit;
-}
-
-notegrp(pid: int, nil: string)
-{
- fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE);
- if(fd != nil)
- sys->fprint(fd, "killgrp");
-}
-
-sendmsg(c: ref Conn, m: ref Msg)
-{
- c.out <-= m;
-}