1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111 |
- /*
- * 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, 0);
- 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[Ndbvlen];
- int n;
- static Ndb *db;
- Ndbtuple *t;
- Ndbs ndbs;
- 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;
- }
- t = ndbgetval(db, &ndbs, "tcp", p, "port", port);
- if(t == nil)
- return -1;
- ndbfree(t);
- return atoi(port);
- }
- 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)){
- closereq(r->oldreq);
- 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);
- }
|