123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /*
- * 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) */
- uint32_t 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;
- uint32_t 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, uint64_t 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];
- uint32_t 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];
- uint32_t 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)
- {
- uint32_t 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 };
- uint32_t 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*)
- {
- uint32_t 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);
- }
|