diff options
author | khm <devnull@localhost> | 2017-01-12 16:36:38 -0800 |
---|---|---|
committer | khm <devnull@localhost> | 2017-01-12 16:36:38 -0800 |
commit | dc8c7bf2b73d608ac2483aee303a51a3507b4c5a (patch) | |
tree | f8c69dbf5f36de6f9acea724f2068054b5b8e7a6 /sys/src/cmd/ssh/sshnet.c | |
parent | cb1555c7d741fa482c339aa9ac8a44753e2ad296 (diff) |
ssh: R.I.P.
Diffstat (limited to 'sys/src/cmd/ssh/sshnet.c')
-rw-r--r-- | sys/src/cmd/ssh/sshnet.c | 1110 |
1 files changed, 0 insertions, 1110 deletions
diff --git a/sys/src/cmd/ssh/sshnet.c b/sys/src/cmd/ssh/sshnet.c deleted file mode 100644 index 1de834c72..000000000 --- a/sys/src/cmd/ssh/sshnet.c +++ /dev/null @@ -1,1110 +0,0 @@ -/* - * SSH network file system. - * Presents remote TCP stack as /net-style file system. - */ - -#include "ssh.h" -#include <bio.h> -#include <ndb.h> -#include <thread.h> -#include <fcall.h> -#include <9p.h> - -int rawhack = 1; -Conn *conn; -char *remoteip = "<remote>"; -char *mtpt; - -Cipher *allcipher[] = { - &cipherrc4, - &cipherblowfish, - &cipher3des, - &cipherdes, - &ciphernone, - &ciphertwiddle, -}; - -Auth *allauth[] = { - &authpassword, - &authrsa, - &authtis, -}; - -char *cipherlist = "rc4 3des"; -char *authlist = "rsa password tis"; - -Cipher* -findcipher(char *name, Cipher **list, int nlist) -{ - int i; - - for(i=0; i<nlist; i++) - if(strcmp(name, list[i]->name) == 0) - return list[i]; - error("unknown cipher %s", name); - return nil; -} - -Auth* -findauth(char *name, Auth **list, int nlist) -{ - int i; - - for(i=0; i<nlist; i++) - if(strcmp(name, list[i]->name) == 0) - return list[i]; - error("unknown auth %s", name); - return nil; -} - -void -usage(void) -{ - fprint(2, "usage: sshnet [-A authlist] [-c cipherlist] [-m mtpt] [user@]hostname\n"); - exits("usage"); -} - -int -isatty(int fd) -{ - char buf[64]; - - buf[0] = '\0'; - fd2path(fd, buf, sizeof buf); - if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0) - return 1; - return 0; -} - -enum -{ - Qroot, - Qcs, - Qtcp, - Qclone, - Qn, - Qctl, - Qdata, - Qlocal, - Qremote, - Qstatus, -}; - -#define PATH(type, n) ((type)|((n)<<8)) -#define TYPE(path) ((int)(path) & 0xFF) -#define NUM(path) ((uint)(path)>>8) - -Channel *sshmsgchan; /* chan(Msg*) */ -Channel *fsreqchan; /* chan(Req*) */ -Channel *fsreqwaitchan; /* chan(nil) */ -Channel *fsclunkchan; /* chan(Fid*) */ -Channel *fsclunkwaitchan; /* chan(nil) */ -ulong time0; - -enum -{ - Closed, - Dialing, - Established, - Teardown, -}; - -char *statestr[] = { - "Closed", - "Dialing", - "Established", - "Teardown", -}; - -typedef struct Client Client; -struct Client -{ - int ref; - int state; - int num; - int servernum; - char *connect; - Req *rq; - Req **erq; - Msg *mq; - Msg **emq; -}; - -int nclient; -Client **client; - -int -newclient(void) -{ - int i; - Client *c; - - for(i=0; i<nclient; i++) - if(client[i]->ref==0 && client[i]->state == Closed) - return i; - - if(nclient%16 == 0) - client = erealloc9p(client, (nclient+16)*sizeof(client[0])); - - c = emalloc9p(sizeof(Client)); - memset(c, 0, sizeof(*c)); - c->num = nclient; - client[nclient++] = c; - return c->num; -} - -void -queuereq(Client *c, Req *r) -{ - if(c->rq==nil) - c->erq = &c->rq; - *c->erq = r; - r->aux = nil; - c->erq = (Req**)&r->aux; -} - -void -queuemsg(Client *c, Msg *m) -{ - if(c->mq==nil) - c->emq = &c->mq; - *c->emq = m; - m->link = nil; - c->emq = (Msg**)&m->link; -} - -void -matchmsgs(Client *c) -{ - Req *r; - Msg *m; - int n, rm; - - while(c->rq && c->mq){ - r = c->rq; - c->rq = r->aux; - - rm = 0; - m = c->mq; - n = r->ifcall.count; - if(n >= m->ep - m->rp){ - n = m->ep - m->rp; - c->mq = m->link; - rm = 1; - } - memmove(r->ofcall.data, m->rp, n); - if(rm) - free(m); - else - m->rp += n; - r->ofcall.count = n; - respond(r, nil); - } -} - -Req* -findreq(Client *c, Req *r) -{ - Req **l; - - for(l=&c->rq; *l; l=(Req**)&(*l)->aux){ - if(*l == r){ - *l = r->aux; - if(*l == nil) - c->erq = l; - return r; - } - } - return nil; -} - -void -dialedclient(Client *c) -{ - Req *r; - - if(r=c->rq){ - if(r->aux != nil) - sysfatal("more than one outstanding dial request (BUG)"); - if(c->state == Established) - respond(r, nil); - else - respond(r, "connect failed"); - } - c->rq = nil; -} - -void -teardownclient(Client *c) -{ - Msg *m; - - c->state = Teardown; - m = allocmsg(conn, SSH_MSG_CHANNEL_INPUT_EOF, 4); - putlong(m, c->servernum); - sendmsg(m); -} - -void -hangupclient(Client *c) -{ - Req *r, *next; - Msg *m, *mnext; - - c->state = Closed; - for(m=c->mq; m; m=mnext){ - mnext = m->link; - free(m); - } - c->mq = nil; - for(r=c->rq; r; r=next){ - next = r->aux; - respond(r, "hangup on network connection"); - } - c->rq = nil; -} - -void -closeclient(Client *c) -{ - Msg *m, *next; - - if(--c->ref) - return; - - if(c->rq != nil) - sysfatal("ref count reached zero with requests pending (BUG)"); - - for(m=c->mq; m; m=next){ - next = m->link; - free(m); - } - c->mq = nil; - - if(c->state != Closed) - teardownclient(c); -} - - -void -sshreadproc(void *a) -{ - Conn *c; - Msg *m; - - c = a; - for(;;){ - m = recvmsg(c, -1); - if(m == nil) - sysfatal("eof on ssh connection"); - sendp(sshmsgchan, m); - } -} - -typedef struct Tab Tab; -struct Tab -{ - char *name; - ulong mode; -}; - -Tab tab[] = -{ - "/", DMDIR|0555, - "cs", 0666, - "tcp", DMDIR|0555, - "clone", 0666, - nil, DMDIR|0555, - "ctl", 0666, - "data", 0666, - "local", 0444, - "remote", 0444, - "status", 0444, -}; - -static void -fillstat(Dir *d, uvlong path) -{ - Tab *t; - - memset(d, 0, sizeof(*d)); - d->uid = estrdup9p("ssh"); - d->gid = estrdup9p("ssh"); - d->qid.path = path; - d->atime = d->mtime = time0; - t = &tab[TYPE(path)]; - if(t->name) - d->name = estrdup9p(t->name); - else{ - d->name = smprint("%ud", NUM(path)); - if(d->name == nil) - sysfatal("out of memory"); - } - d->qid.type = t->mode>>24; - d->mode = t->mode; -} - -static void -fsattach(Req *r) -{ - if(r->ifcall.aname && r->ifcall.aname[0]){ - respond(r, "invalid attach specifier"); - return; - } - r->fid->qid.path = PATH(Qroot, 0); - r->fid->qid.type = QTDIR; - r->fid->qid.vers = 0; - r->ofcall.qid = r->fid->qid; - respond(r, nil); -} - -static void -fsstat(Req *r) -{ - fillstat(&r->d, r->fid->qid.path); - respond(r, nil); -} - -static int -rootgen(int i, Dir *d, void*) -{ - i += Qroot+1; - if(i <= Qtcp){ - fillstat(d, i); - return 0; - } - return -1; -} - -static int -tcpgen(int i, Dir *d, void*) -{ - i += Qtcp+1; - if(i < Qn){ - fillstat(d, i); - return 0; - } - i -= Qn; - if(i < nclient){ - fillstat(d, PATH(Qn, i)); - return 0; - } - return -1; -} - -static int -clientgen(int i, Dir *d, void *aux) -{ - Client *c; - - c = aux; - i += Qn+1; - if(i <= Qstatus){ - fillstat(d, PATH(i, c->num)); - return 0; - } - return -1; -} - -static char* -fswalk1(Fid *fid, char *name, Qid *qid) -{ - int i, n; - char buf[32]; - ulong path; - - path = fid->qid.path; - if(!(fid->qid.type&QTDIR)) - return "walk in non-directory"; - - if(strcmp(name, "..") == 0){ - switch(TYPE(path)){ - case Qn: - qid->path = PATH(Qtcp, NUM(path)); - qid->type = tab[Qtcp].mode>>24; - return nil; - case Qtcp: - qid->path = PATH(Qroot, 0); - qid->type = tab[Qroot].mode>>24; - return nil; - case Qroot: - return nil; - default: - return "bug in fswalk1"; - } - } - - i = TYPE(path)+1; - for(; i<nelem(tab); i++){ - if(i==Qn){ - n = atoi(name); - snprint(buf, sizeof buf, "%d", n); - if(n < nclient && strcmp(buf, name) == 0){ - qid->path = PATH(i, n); - qid->type = tab[i].mode>>24; - return nil; - } - break; - } - if(strcmp(name, tab[i].name) == 0){ - qid->path = PATH(i, NUM(path)); - qid->type = tab[i].mode>>24; - return nil; - } - if(tab[i].mode&DMDIR) - break; - } - return "directory entry not found"; -} - -typedef struct Cs Cs; -struct Cs -{ - char *resp; - int isnew; -}; - -static int -ndbfindport(char *p) -{ - char *s, *port; - int n; - static Ndb *db; - - if(*p == '\0') - return -1; - - n = strtol(p, &s, 0); - if(*s == '\0') - return n; - - if(db == nil){ - db = ndbopen("/lib/ndb/common"); - if(db == nil) - return -1; - } - - port = ndbgetvalue(db, nil, "tcp", p, "port", nil); - if(port == nil) - return -1; - n = atoi(port); - free(port); - - return n; -} - -static void -csread(Req *r) -{ - Cs *cs; - - cs = r->fid->aux; - if(cs->resp==nil){ - respond(r, "cs read without write"); - return; - } - if(r->ifcall.offset==0){ - if(!cs->isnew){ - r->ofcall.count = 0; - respond(r, nil); - return; - } - cs->isnew = 0; - } - readstr(r, cs->resp); - respond(r, nil); -} - -static void -cswrite(Req *r) -{ - int port, nf; - char err[ERRMAX], *f[4], *s, *ns; - Cs *cs; - - cs = r->fid->aux; - s = emalloc(r->ifcall.count+1); - memmove(s, r->ifcall.data, r->ifcall.count); - s[r->ifcall.count] = '\0'; - - nf = getfields(s, f, nelem(f), 0, "!"); - if(nf != 3){ - free(s); - respond(r, "can't translate"); - return; - } - if(strcmp(f[0], "tcp") != 0 && strcmp(f[0], "net") != 0){ - free(s); - respond(r, "unknown protocol"); - return; - } - port = ndbfindport(f[2]); - if(port <= 0){ - free(s); - respond(r, "no translation found"); - return; - } - - ns = smprint("%s/tcp/clone %s!%d", mtpt, f[1], port); - if(ns == nil){ - free(s); - rerrstr(err, sizeof err); - respond(r, err); - return; - } - free(s); - free(cs->resp); - cs->resp = ns; - cs->isnew = 1; - r->ofcall.count = r->ifcall.count; - respond(r, nil); -} - -static void -ctlread(Req *r, Client *c) -{ - char buf[32]; - - sprint(buf, "%d", c->num); - readstr(r, buf); - respond(r, nil); -} - -static void -ctlwrite(Req *r, Client *c) -{ - char *f[3], *s; - int nf; - Msg *m; - - s = emalloc(r->ifcall.count+1); - memmove(s, r->ifcall.data, r->ifcall.count); - s[r->ifcall.count] = '\0'; - - nf = tokenize(s, f, 3); - if(nf == 0){ - free(s); - respond(r, nil); - return; - } - - if(strcmp(f[0], "hangup") == 0){ - if(c->state != Established) - goto Badarg; - if(nf != 1) - goto Badarg; - queuereq(c, r); - teardownclient(c); - }else if(strcmp(f[0], "connect") == 0){ - if(c->state != Closed) - goto Badarg; - if(nf != 2) - goto Badarg; - c->connect = estrdup9p(f[1]); - nf = getfields(f[1], f, nelem(f), 0, "!"); - if(nf != 2){ - free(c->connect); - c->connect = nil; - goto Badarg; - } - c->state = Dialing; - m = allocmsg(conn, SSH_MSG_PORT_OPEN, 4+4+strlen(f[0])+4+4+strlen("localhost")); - putlong(m, c->num); - putstring(m, f[0]); - putlong(m, ndbfindport(f[1])); - putstring(m, "localhost"); - queuereq(c, r); - sendmsg(m); - }else{ - Badarg: - respond(r, "bad or inappropriate tcp control message"); - } - free(s); -} - -static void -dataread(Req *r, Client *c) -{ - if(c->state != Established){ - respond(r, "not connected"); - return; - } - queuereq(c, r); - matchmsgs(c); -} - -static void -datawrite(Req *r, Client *c) -{ - Msg *m; - - if(c->state != Established){ - respond(r, "not connected"); - return; - } - if(r->ifcall.count){ - m = allocmsg(conn, SSH_MSG_CHANNEL_DATA, 4+4+r->ifcall.count); - putlong(m, c->servernum); - putlong(m, r->ifcall.count); - putbytes(m, r->ifcall.data, r->ifcall.count); - sendmsg(m); - } - r->ofcall.count = r->ifcall.count; - respond(r, nil); -} - -static void -localread(Req *r) -{ - char buf[128]; - - snprint(buf, sizeof buf, "%s!%d\n", remoteip, 0); - readstr(r, buf); - respond(r, nil); -} - -static void -remoteread(Req *r, Client *c) -{ - char *s; - char buf[128]; - - s = c->connect; - if(s == nil) - s = "::!0"; - snprint(buf, sizeof buf, "%s\n", s); - readstr(r, buf); - respond(r, nil); -} - -static void -statusread(Req *r, Client *c) -{ - char buf[64]; - char *s; - - snprint(buf, sizeof buf, "%s!%d", remoteip, 0); - s = statestr[c->state]; - readstr(r, s); - respond(r, nil); -} - -static void -fsread(Req *r) -{ - char e[ERRMAX]; - ulong path; - - path = r->fid->qid.path; - switch(TYPE(path)){ - default: - snprint(e, sizeof e, "bug in fsread path=%lux", path); - respond(r, e); - break; - - case Qroot: - dirread9p(r, rootgen, nil); - respond(r, nil); - break; - - case Qcs: - csread(r); - break; - - case Qtcp: - dirread9p(r, tcpgen, nil); - respond(r, nil); - break; - - case Qn: - dirread9p(r, clientgen, client[NUM(path)]); - respond(r, nil); - break; - - case Qctl: - ctlread(r, client[NUM(path)]); - break; - - case Qdata: - dataread(r, client[NUM(path)]); - break; - - case Qlocal: - localread(r); - break; - - case Qremote: - remoteread(r, client[NUM(path)]); - break; - - case Qstatus: - statusread(r, client[NUM(path)]); - break; - } -} - -static void -fswrite(Req *r) -{ - ulong path; - char e[ERRMAX]; - - path = r->fid->qid.path; - switch(TYPE(path)){ - default: - snprint(e, sizeof e, "bug in fswrite path=%lux", path); - respond(r, e); - break; - - case Qcs: - cswrite(r); - break; - - case Qctl: - ctlwrite(r, client[NUM(path)]); - break; - - case Qdata: - datawrite(r, client[NUM(path)]); - break; - } -} - -static void -fsopen(Req *r) -{ - static int need[4] = { 4, 2, 6, 1 }; - ulong path; - int n; - Tab *t; - Cs *cs; - - /* - * lib9p already handles the blatantly obvious. - * we just have to enforce the permissions we have set. - */ - path = r->fid->qid.path; - t = &tab[TYPE(path)]; - n = need[r->ifcall.mode&3]; - if((n&t->mode) != n){ - respond(r, "permission denied"); - return; - } - - switch(TYPE(path)){ - case Qcs: - cs = emalloc(sizeof(Cs)); - r->fid->aux = cs; - respond(r, nil); - break; - case Qclone: - n = newclient(); - path = PATH(Qctl, n); - r->fid->qid.path = path; - r->ofcall.qid.path = path; - if(chatty9p) - fprint(2, "open clone => path=%lux\n", path); - t = &tab[Qctl]; - /* fall through */ - default: - if(t-tab >= Qn) - client[NUM(path)]->ref++; - respond(r, nil); - break; - } -} - -static void -fsflush(Req *r) -{ - int i; - - for(i=0; i<nclient; i++) - if(findreq(client[i], r->oldreq)) - respond(r->oldreq, "interrupted"); - respond(r, nil); -} - -static void -handlemsg(Msg *m) -{ - int chan, n; - Client *c; - - switch(m->type){ - case SSH_MSG_DISCONNECT: - case SSH_CMSG_EXIT_CONFIRMATION: - sysfatal("disconnect"); - - case SSH_CMSG_STDIN_DATA: - case SSH_CMSG_EOF: - case SSH_CMSG_WINDOW_SIZE: - /* don't care */ - free(m); - break; - - case SSH_MSG_CHANNEL_DATA: - chan = getlong(m); - n = getlong(m); - if(m->rp+n != m->ep) - sysfatal("got bad channel data"); - if(chan<nclient && (c=client[chan])->state==Established){ - queuemsg(c, m); - matchmsgs(c); - }else - free(m); - break; - - case SSH_MSG_CHANNEL_INPUT_EOF: - chan = getlong(m); - free(m); - if(chan<nclient){ - c = client[chan]; - chan = c->servernum; - hangupclient(c); - m = allocmsg(conn, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4); - putlong(m, chan); - sendmsg(m); - } - break; - - case SSH_MSG_CHANNEL_OUTPUT_CLOSED: - chan = getlong(m); - if(chan<nclient) - hangupclient(client[chan]); - free(m); - break; - - case SSH_MSG_CHANNEL_OPEN_CONFIRMATION: - chan = getlong(m); - c = nil; - if(chan>=nclient || (c=client[chan])->state != Dialing){ - if(c) - fprint(2, "cstate %d\n", c->state); - sysfatal("got unexpected open confirmation for %d", chan); - } - c->servernum = getlong(m); - c->state = Established; - dialedclient(c); - free(m); - break; - - case SSH_MSG_CHANNEL_OPEN_FAILURE: - chan = getlong(m); - c = nil; - if(chan>=nclient || (c=client[chan])->state != Dialing) - sysfatal("got unexpected open failure"); - if(m->rp+4 <= m->ep) - c->servernum = getlong(m); - c->state = Closed; - dialedclient(c); - free(m); - break; - } -} - -void -fsnetproc(void*) -{ - ulong path; - Alt a[4]; - Cs *cs; - Fid *fid; - Req *r; - Msg *m; - - threadsetname("fsthread"); - - a[0].op = CHANRCV; - a[0].c = fsclunkchan; - a[0].v = &fid; - a[1].op = CHANRCV; - a[1].c = fsreqchan; - a[1].v = &r; - a[2].op = CHANRCV; - a[2].c = sshmsgchan; - a[2].v = &m; - a[3].op = CHANEND; - - for(;;){ - switch(alt(a)){ - case 0: - path = fid->qid.path; - switch(TYPE(path)){ - case Qcs: - cs = fid->aux; - if(cs){ - free(cs->resp); - free(cs); - } - break; - } - if(fid->omode != -1 && TYPE(path) >= Qn) - closeclient(client[NUM(path)]); - sendp(fsclunkwaitchan, nil); - break; - case 1: - switch(r->ifcall.type){ - case Tattach: - fsattach(r); - break; - case Topen: - fsopen(r); - break; - case Tread: - fsread(r); - break; - case Twrite: - fswrite(r); - break; - case Tstat: - fsstat(r); - break; - case Tflush: - fsflush(r); - break; - default: - respond(r, "bug in fsthread"); - break; - } - sendp(fsreqwaitchan, 0); - break; - case 2: - handlemsg(m); - break; - } - } -} - -static void -fssend(Req *r) -{ - sendp(fsreqchan, r); - recvp(fsreqwaitchan); /* avoids need to deal with spurious flushes */ -} - -static void -fsdestroyfid(Fid *fid) -{ - sendp(fsclunkchan, fid); - recvp(fsclunkwaitchan); -} - -void -takedown(Srv*) -{ - threadexitsall("done"); -} - -Srv fs = -{ -.attach= fssend, -.destroyfid= fsdestroyfid, -.walk1= fswalk1, -.open= fssend, -.read= fssend, -.write= fssend, -.stat= fssend, -.flush= fssend, -.end= takedown, -}; - -void -threadmain(int argc, char **argv) -{ - int i, fd; - char *host, *user, *p, *service; - char *f[16]; - Msg *m; - static Conn c; - - fmtinstall('B', mpfmt); - fmtinstall('H', encodefmt); - - mtpt = "/net"; - service = nil; - user = nil; - ARGBEGIN{ - case 'B': /* undocumented, debugging */ - doabort = 1; - break; - case 'D': /* undocumented, debugging */ - debuglevel = strtol(EARGF(usage()), nil, 0); - break; - case '9': /* undocumented, debugging */ - chatty9p++; - break; - - case 'A': - authlist = EARGF(usage()); - break; - case 'c': - cipherlist = EARGF(usage()); - break; - case 'm': - mtpt = EARGF(usage()); - break; - case 's': - service = EARGF(usage()); - break; - default: - usage(); - }ARGEND - - if(argc != 1) - usage(); - - host = argv[0]; - - if((p = strchr(host, '@')) != nil){ - *p++ = '\0'; - user = host; - host = p; - } - if(user == nil) - user = getenv("user"); - if(user == nil) - sysfatal("cannot find user name"); - - privatefactotum(); - - if((fd = dial(netmkaddr(host, "tcp", "ssh"), nil, nil, nil)) < 0) - sysfatal("dialing %s: %r", host); - - c.interactive = isatty(0); - c.fd[0] = c.fd[1] = fd; - c.user = user; - c.host = host; - setaliases(&c, host); - - c.nokcipher = getfields(cipherlist, f, nelem(f), 1, ", "); - c.okcipher = emalloc(sizeof(Cipher*)*c.nokcipher); - for(i=0; i<c.nokcipher; i++) - c.okcipher[i] = findcipher(f[i], allcipher, nelem(allcipher)); - - c.nokauth = getfields(authlist, f, nelem(f), 1, ", "); - c.okauth = emalloc(sizeof(Auth*)*c.nokauth); - for(i=0; i<c.nokauth; i++) - c.okauth[i] = findauth(f[i], allauth, nelem(allauth)); - - sshclienthandshake(&c); - - requestpty(&c); /* turns on TCP_NODELAY on other side */ - m = allocmsg(&c, SSH_CMSG_EXEC_SHELL, 0); - sendmsg(m); - - time0 = time(0); - sshmsgchan = chancreate(sizeof(Msg*), 16); - fsreqchan = chancreate(sizeof(Req*), 0); - fsreqwaitchan = chancreate(sizeof(void*), 0); - fsclunkchan = chancreate(sizeof(Fid*), 0); - fsclunkwaitchan = chancreate(sizeof(void*), 0); - - conn = &c; - procrfork(sshreadproc, &c, 8192, RFNAMEG|RFNOTEG); - procrfork(fsnetproc, nil, 8192, RFNAMEG|RFNOTEG); - - threadpostmountsrv(&fs, service, mtpt, MREPL); - exits(0); -} - |