summaryrefslogtreecommitdiff
path: root/appl/cmd/ssh/sshserve.b
diff options
context:
space:
mode:
authorforsyth <forsyth@vitanuova.com>2011-01-17 11:10:35 +0000
committerforsyth <forsyth@vitanuova.com>2011-01-17 11:10:35 +0000
commitd6b4eae8eb0a5ca3119414005e483fedd63a62d6 (patch)
tree4959b04b1ae02ce5ccb4b3c0a8c459ff46587eb7 /appl/cmd/ssh/sshserve.b
parent9e6910dc0c747c8f30b87f6482f4eadb48ad6654 (diff)
20110117-1110
Diffstat (limited to 'appl/cmd/ssh/sshserve.b')
-rw-r--r--appl/cmd/ssh/sshserve.b495
1 files changed, 0 insertions, 495 deletions
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;
-}