/* * 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;} voidusage(void){ fprint(2, "usage: sshnet [-A authlist] [-c cipherlist] [-m mtpt] [user@]hostname\n"); exits("usage");} intisatty(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; intnewclient(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;} voidqueuereq(Client *c, Req *r){ if(c->rq==nil) c->erq = &c->rq; *c->erq = r; r->aux = nil; c->erq = (Req**)&r->aux;} voidqueuemsg(Client *c, Msg *m){ if(c->mq==nil) c->emq = &c->mq; *c->emq = m; m->link = nil; c->emq = (Msg**)&m->link;} voidmatchmsgs(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;} voiddialedclient(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;} voidteardownclient(Client *c){ Msg *m; c->state = Teardown; m = allocmsg(conn, SSH_MSG_CHANNEL_INPUT_EOF, 4); putlong(m, c->servernum); sendmsg(m);} voidhangupclient(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;} voidcloseclient(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);} voidsshreadproc(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 voidfillstat(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 voidfsattach(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 voidfsstat(Req *r){ fillstat(&r->d, r->fid->qid.path); respond(r, nil);} static introotgen(int i, Dir *d, void*){ i += Qroot+1; if(i <= Qtcp){ fillstat(d, i); return 0; } return -1;} static inttcpgen(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 intclientgen(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 intndbfindport(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 voidcsread(Req *r){ Cs *cs; Lines 1–500 of 1110. Load more
/* * 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;