#include <u.h>#include <libc.h>#include <mp.h>#include <fcall.h>#include <thread.h>#include <9p.h>#include <auth.h>#include <authsrv.h>#include <libsec.h>#include <ip.h>#include "sshtun.h" void stend(Srv *);void server(char *, char *);void stopen(Req *);void stlisten1(void *);void stlisten2(void *);void stread(Req *);void readreqrem(void *);void readdata(void *);void stwrite(Req *);void writectl(void *);void writereqrem(void *);void writedata(void *);void stclunk(Fid *);void stflush(Req *);void filedup(Req *, File *);Conn *alloc_conn(void);SSHChan *alloc_chan(Conn *);int dohandshake(Conn *, char *);void send_kexinit(Conn *);void reader(void *);int validatekex(Conn *, Packet *);int validatekexs(Packet *);int validatekexc(Packet *);int auth_req(Packet *, Conn *);int client_auth(Conn *, Ioproc *);char *factlookup(int, int, char *[]);void shutdown(Conn *); Srv sshtunsrv = { .open = stopen, .read = stread, .write = stwrite, .flush = stflush, .destroyfid = stclunk, .end = stend,}; Cipher *cryptos[] = { &cipheraes128, &cipheraes192, &cipheraes256,// &cipherblowfish, &cipher3des, &cipherrc4,}; Kex *kexes[] = { &dh1sha1, &dh14sha1,}; PKA *pkas[3]; #define Ctl(x) (1+(x)-'A') static uchar stty_cooked[] = { 0x01, 0, 0, 0, 0x7f, /* interrupt = DEL */ 0x02, 0, 0, 0, Ctl('Q'), /* quit */ 0x03, 0, 0, 0, Ctl('H'), /* backspace */ 0x04, 0, 0, 0, Ctl('U'), /* line kill */ 0x05, 0, 0, 0, Ctl('D'), /* EOF */ 0x35, 0, 0, 0, 0, /* echo */ 0x48, 0, 0, 0, 0, /* opost */ 0, /* end of list */}; char *macnames[] = { "hmac-sha1",}; char *st_names[] = {[Empty] "Empty",[Allocated] "Allocated",[Initting] "Initting",[Listening] "Listening",[Opening] "Opening",[Negotiating] "Negotiating",[Authing] "Authing",[Established] "Established",[Eof] "Eof",[Closing] "Closing",[Closed] "Closed",}; File *rootfile, *clonefile, *ctlfile, *keysfile;Conn *connections[MAXCONN];char *mntpt = "/net";int debug;int kflag;int slfd;char uid[32];MBox keymbox;QLock availlck;Rendez availrend; voidusage(void){ fprint(2, "usage: sshtun [-d] [-k] [-m mntpt] [-s srvpt]\n"); exits("usage");} voidthreadmain(int argc, char *argv[]){ char *srvpt = nil; int fd, n; slfd = open("/dev/syslog", OWRITE); ARGBEGIN { case '9': chatty9p = 1; break; case 'd': debug++; break; case 'k': kflag = 1; break; case 'm': mntpt = EARGF(usage()); break; case 's': srvpt = EARGF(usage()); break; default: usage(); break; } ARGEND; fd = open("/dev/user", OREAD); if (fd < 0) strcpy(uid, "none"); else { n = read(fd, uid, 31); if (n < 0) strcpy(uid, "none"); else uid[n] = '\0'; close(fd); } keymbox.mchan = chancreate(4, 0); availrend.l = &availlck; dh_init(pkas); if (rfork(RFNOTEG) < 0) fprint(2, "Failed to set process attributes: %r\n"); /* isolate us from any output pipe, e.g. "ssh fred | conswdir" pipeline */ close(0); close(1); server(mntpt, srvpt);} Ioproc *io9p; intread9pmsg(int fd, void *abuf, uint n){ int m, len; uchar *buf; if (io9p == nil) io9p = ioproc(); buf = abuf; /* read count */ m = ioreadn(io9p, fd, buf, BIT32SZ); if(m != BIT32SZ){ if(m < 0) return -1; return 0; } len = GBIT32(buf); if(len <= BIT32SZ || len > n){ werrstr("bad length in 9P2000 message header"); return -1; } len -= BIT32SZ; m = ioreadn(io9p, fd, buf+BIT32SZ, len); if(m < len) return 0; return BIT32SZ+m;} voidstend(Srv *){ closeioproc(io9p); threadkillgrp(threadgetgrp());} voidserver(char *mntpt, char *srvpt){ Dir d; char *p; int fd; sshtunsrv.tree = alloctree(uid, uid, 0777, nil); rootfile = createfile(sshtunsrv.tree->root, "ssh", uid, 0555|DMDIR, (void*)RootFile); clonefile = createfile(rootfile, "clone", uid, 0666, (void*)CloneFile); ctlfile = createfile(rootfile, "ctl", uid, 0666, (void*)CtlFile); keysfile = createfile(rootfile, "keys", uid, 0600, (void *)ReqRemFile); threadpostmountsrv(&sshtunsrv, srvpt, mntpt, MAFTER); p = smprint("%s/cs", mntpt); fd = open(p, OWRITE); free(p); if (fd >= 0) { fprint(fd, "add ssh"); close(fd); } if (srvpt) { nulldir(&d); d.mode = 0666; p = smprint("/srv/%s", srvpt); dirwstat(p, &d); free(p); }} voidstopen(Req *r){ Conn *c; SSHChan *sc; char *p; int lev, xconn, fnum, fd; char buf[10]; fnum = (uintptr)r->fid->file->aux; lev = fnum >> LEVSHIFT; switch (fnum & FileMask) { case CloneFile: switch (lev) { case 0: p = smprint("%s/tcp/clone", mntpt); fd = open(p, ORDWR); free(p); if (fd < 0) { responderror(r); return; } c = alloc_conn(); if (c == nil) { respond(r, "No more connections"); return; } c->ctlfd = fd; filedup(r, c->ctlfile); if (debug) fprint(2, "new connection: %d\n", c->id); break; case 1: xconn = (fnum >> CONNSHIFT) & ConnMask; c = connections[xconn]; if (c == nil) { respond(r, "Invalid connection"); return; } sc = alloc_chan(c); if (sc == nil) { respond(r, "No more channels"); return; } filedup(r, sc->ctl); break; default: snprint(buf, 10, "bad %d", lev); readstr(r, buf); break; } respond(r, nil); break; case ListenFile: switch (lev) { case 1: r->aux = (void *)threadcreate(stlisten1, r, 8192); break; case 2: r->aux = (void *)threadcreate(stlisten2, r, 8192); break; default: respond(r, "not possible"); break; } break; default: respond(r, nil); break; }} voidstlisten1(void *a){ Req *r; Conn *c, *cl; Ioproc *io; char *msg; int fnum, xconn, fd, n; char buf[10], path[40]; r = a; fnum = (uintptr)r->fid->file->aux; xconn = (fnum >> CONNSHIFT) & ConnMask; cl = connections[xconn]; if (cl == nil) { respond(r, "Invalid connection"); threadexits(nil); } memset(buf, '\0', sizeof(buf)); io = ioproc(); seek(cl->ctlfd, 0, 0); if ((n = ioread(io, cl->ctlfd, buf, 10)) <= 0) fprint(2, "read failed: %r\n"); buf[n] = '\0'; cl->state = Listening; snprint(path, 40, "%s/tcp/%s/listen", mntpt, buf); while (1) { fd = ioopen(io, path, ORDWR); if (fd < 0) { r->aux = 0; responderror(r); closeioproc(io); shutdown(cl); threadexits(nil); } c = alloc_conn(); if (c) break; n = ioread(io, fd, buf, 10); if (n <= 0) { r->aux = 0; responderror(r); closeioproc(io); shutdown(cl); threadexits(nil); } else { buf[n] = '\0'; msg = smprint("reject %s No available connections", buf); iowrite(io, fd, msg, strlen(msg)); free(msg); } close(fd); } c->ctlfd = fd; filedup(r, c->ctlfile); if (debug) fprint(2, "**** responding to listen open ***\n"); r->aux = 0; respond(r, nil); closeioproc(io); threadexits(nil);} voidstlisten2(void *a){ Req *r; Packet *p2; Ioproc *io; Conn *c; SSHChan *sc; int i, n, xconn, fnum; r = a; fnum = (uintptr)r->fid->file->aux; xconn = (fnum >> CONNSHIFT) & ConnMask; c = connections[xconn]; if (c == nil) { respond(r, "Invalid connection"); threadexits(nil); } if (c->state == Closed || c->state == Closing) { r->aux = 0; respond(r, "listen on a closed connection"); threadexits(nil); } sc = c->chans[fnum & ConnMask]; qlock(&c->l); sc->lreq = r; for (i = 0; i < c->nchan; ++i) if (c->chans[i] && c->chans[i]->state == Opening && c->chans[i]->ann && strcmp(c->chans[i]->ann, sc->ann) == 0) break; if (i >= c->nchan) { sc->state = Listening; rsleep(&sc->r); i = sc->waker; if (i < 0) { qunlock(&c->l); r->aux = 0; responderror(r); threadexits(nil); } } else rwakeup(&c->chans[i]->r); qunlock(&c->l); if (c->state == Closed || c->state == Closing || c->state == Eof) { r->aux = 0; respond(r, "Listen on a closed connection"); threadexits(nil); } c->chans[i]->state = Established; p2 = new_packet(c); c->chans[i]->rwindow = 32*1024; add_byte(p2, SSH_MSG_CHANNEL_OPEN_CONFIRMATION); hnputl(p2->payload + 1, c->chans[i]->otherid); hnputl(p2->payload + 5, c->chans[i]->id); hnputl(p2->payload + 9, 32*1024); hnputl(p2->payload + 13, 8192); p2->rlength = 18; n = finish_packet(p2); filedup(r, c->chans[i]->ctl); io = ioproc(); n = iowrite(io, c->datafd, p2->nlength, n); free(p2); closeioproc(io); if (debug) fprint(2, "*** Responding to chan listen open ***\n"); r->aux = 0; if (n < 0) responderror(r); else respond(r, nil); threadexits(nil);} voidgetdata(Conn *c, SSHChan *sc, Req *r){ Packet *p; Plist *d; int n; n = r->ifcall.count; if (sc->dataq->rem < n) n = sc->dataq->rem; if (n > 8192) n = 8192; r->ifcall.offset = 0; readbuf(r, sc->dataq->st, n); sc->dataq->st += n; sc->dataq->rem -= n; sc->inrqueue -= n; if (sc->dataq->rem <= 0) { d = sc->dataq; sc->dataq = sc->dataq->next; if (d->pack->tlength > sc->rwindow) sc->rwindow = 0; else sc->rwindow -= d->pack->tlength; free(d->pack); free(d); } if (sc->rwindow < 16*1024) { sc->rwindow += 32*1024; if (debug) fprint(2, "Increasing receive window to %lud, inq %lud\n", sc->rwindow, sc->inrqueue); p = new_packet(c); add_byte(p, SSH_MSG_CHANNEL_WINDOW_ADJUST); hnputl(p->payload+1, sc->otherid); hnputl(p->payload+5, 32*1024); p->rlength += 8; n = finish_packet(p); iowrite(c->dio, c->datafd, p->nlength, n); free(p); } r->aux = 0; respond(r, nil);} voidstread(Req *r){ Conn *c; SSHChan *sc; int fd, n, lev, cnum, xconn, fnum; char buf[256], path[40]; fnum = (uintptr)r->fid->file->aux;Lines 1–500 of 2901. Load more
#include <u.h> #include <libc.h> #include <mp.h> #include <fcall.h> #include <thread.h> #include <9p.h> #include <auth.h> #include <authsrv.h> #include <libsec.h> #include <ip.h> #include "sshtun.h" void stend(Srv *); void server(char *, char *); void stopen(Req *); void stlisten1(void *); void stlisten2(void *); void stread(Req *); void readreqrem(void *); void readdata(void *); void stwrite(Req *); void writectl(void *); void writereqrem(void *); void writedata(void *); void stclunk(Fid *); void stflush(Req *); void filedup(Req *, File *); Conn *alloc_conn(void); SSHChan *alloc_chan(Conn *); int dohandshake(Conn *, char *); void send_kexinit(Conn *); void reader(void *); int validatekex(Conn *, Packet *); int validatekexs(Packet *); int validatekexc(Packet *); int auth_req(Packet *, Conn *); int client_auth(Conn *, Ioproc *); char *factlookup(int, int, char *[]); void shutdown(Conn *); Srv sshtunsrv = { .open = stopen, .read = stread, .write = stwrite, .flush = stflush, .destroyfid = stclunk, .end = stend, }; Cipher *cryptos[] = { &cipheraes128, &cipheraes192, &cipheraes256, // &cipherblowfish, &cipher3des, &cipherrc4, }; Kex *kexes[] = { &dh1sha1, &dh14sha1, }; PKA *pkas[3]; #define Ctl(x) (1+(x)-'A') static uchar stty_cooked[] = { 0x01, 0, 0, 0, 0x7f, /* interrupt = DEL */ 0x02, 0, 0, 0, Ctl('Q'), /* quit */ 0x03, 0, 0, 0, Ctl('H'), /* backspace */ 0x04, 0, 0, 0, Ctl('U'), /* line kill */ 0x05, 0, 0, 0, Ctl('D'), /* EOF */ 0x35, 0, 0, 0, 0, /* echo */ 0x48, 0, 0, 0, 0, /* opost */ 0, /* end of list */ }; char *macnames[] = { "hmac-sha1", }; char *st_names[] = { [Empty] "Empty", [Allocated] "Allocated", [Initting] "Initting", [Listening] "Listening", [Opening] "Opening", [Negotiating] "Negotiating", [Authing] "Authing", [Established] "Established", [Eof] "Eof", [Closing] "Closing", [Closed] "Closed", }; File *rootfile, *clonefile, *ctlfile, *keysfile; Conn *connections[MAXCONN]; char *mntpt = "/net"; int debug; int kflag; int slfd; char uid[32]; MBox keymbox; QLock availlck; Rendez availrend; void usage(void) { fprint(2, "usage: sshtun [-d] [-k] [-m mntpt] [-s srvpt]\n"); exits("usage"); } void threadmain(int argc, char *argv[]) { char *srvpt = nil; int fd, n; slfd = open("/dev/syslog", OWRITE); ARGBEGIN { case '9': chatty9p = 1; break; case 'd': debug++; break; case 'k': kflag = 1; break; case 'm': mntpt = EARGF(usage()); break; case 's': srvpt = EARGF(usage()); break; default: usage(); break; } ARGEND; fd = open("/dev/user", OREAD); if (fd < 0) strcpy(uid, "none"); else { n = read(fd, uid, 31); if (n < 0) strcpy(uid, "none"); else uid[n] = '\0'; close(fd); } keymbox.mchan = chancreate(4, 0); availrend.l = &availlck; dh_init(pkas); if (rfork(RFNOTEG) < 0) fprint(2, "Failed to set process attributes: %r\n"); /* isolate us from any output pipe, e.g. "ssh fred | conswdir" pipeline */ close(0); close(1); server(mntpt, srvpt); } Ioproc *io9p; int read9pmsg(int fd, void *abuf, uint n) { int m, len; uchar *buf; if (io9p == nil) io9p = ioproc(); buf = abuf; /* read count */ m = ioreadn(io9p, fd, buf, BIT32SZ); if(m != BIT32SZ){ if(m < 0) return -1; return 0; } len = GBIT32(buf); if(len <= BIT32SZ || len > n){ werrstr("bad length in 9P2000 message header"); return -1; } len -= BIT32SZ; m = ioreadn(io9p, fd, buf+BIT32SZ, len); if(m < len) return 0; return BIT32SZ+m; } void stend(Srv *) { closeioproc(io9p); threadkillgrp(threadgetgrp()); } void server(char *mntpt, char *srvpt) { Dir d; char *p; int fd; sshtunsrv.tree = alloctree(uid, uid, 0777, nil); rootfile = createfile(sshtunsrv.tree->root, "ssh", uid, 0555|DMDIR, (void*)RootFile); clonefile = createfile(rootfile, "clone", uid, 0666, (void*)CloneFile); ctlfile = createfile(rootfile, "ctl", uid, 0666, (void*)CtlFile); keysfile = createfile(rootfile, "keys", uid, 0600, (void *)ReqRemFile); threadpostmountsrv(&sshtunsrv, srvpt, mntpt, MAFTER); p = smprint("%s/cs", mntpt); fd = open(p, OWRITE); free(p); if (fd >= 0) { fprint(fd, "add ssh"); close(fd); } if (srvpt) { nulldir(&d); d.mode = 0666; p = smprint("/srv/%s", srvpt); dirwstat(p, &d); free(p); } } void stopen(Req *r) { Conn *c; SSHChan *sc; char *p; int lev, xconn, fnum, fd; char buf[10]; fnum = (uintptr)r->fid->file->aux; lev = fnum >> LEVSHIFT; switch (fnum & FileMask) { case CloneFile: switch (lev) { case 0: p = smprint("%s/tcp/clone", mntpt); fd = open(p, ORDWR); free(p); if (fd < 0) { responderror(r); return; } c = alloc_conn(); if (c == nil) { respond(r, "No more connections"); return; } c->ctlfd = fd; filedup(r, c->ctlfile); if (debug) fprint(2, "new connection: %d\n", c->id); break; case 1: xconn = (fnum >> CONNSHIFT) & ConnMask; c = connections[xconn]; if (c == nil) { respond(r, "Invalid connection"); return; } sc = alloc_chan(c); if (sc == nil) { respond(r, "No more channels"); return; } filedup(r, sc->ctl); break; default: snprint(buf, 10, "bad %d", lev); readstr(r, buf); break; } respond(r, nil); break; case ListenFile: switch (lev) { case 1: r->aux = (void *)threadcreate(stlisten1, r, 8192); break; case 2: r->aux = (void *)threadcreate(stlisten2, r, 8192); break; default: respond(r, "not possible"); break; } break; default: respond(r, nil); break; } } void stlisten1(void *a) { Req *r; Conn *c, *cl; Ioproc *io; char *msg; int fnum, xconn, fd, n; char buf[10], path[40]; r = a; fnum = (uintptr)r->fid->file->aux; xconn = (fnum >> CONNSHIFT) & ConnMask; cl = connections[xconn]; if (cl == nil) { respond(r, "Invalid connection"); threadexits(nil); } memset(buf, '\0', sizeof(buf)); io = ioproc(); seek(cl->ctlfd, 0, 0); if ((n = ioread(io, cl->ctlfd, buf, 10)) <= 0) fprint(2, "read failed: %r\n"); buf[n] = '\0'; cl->state = Listening; snprint(path, 40, "%s/tcp/%s/listen", mntpt, buf); while (1) { fd = ioopen(io, path, ORDWR); if (fd < 0) { r->aux = 0; responderror(r); closeioproc(io); shutdown(cl); threadexits(nil); } c = alloc_conn(); if (c) break; n = ioread(io, fd, buf, 10); if (n <= 0) { r->aux = 0; responderror(r); closeioproc(io); shutdown(cl); threadexits(nil); } else { buf[n] = '\0'; msg = smprint("reject %s No available connections", buf); iowrite(io, fd, msg, strlen(msg)); free(msg); } close(fd); } c->ctlfd = fd; filedup(r, c->ctlfile); if (debug) fprint(2, "**** responding to listen open ***\n"); r->aux = 0; respond(r, nil); closeioproc(io); threadexits(nil); } void stlisten2(void *a) { Req *r; Packet *p2; Ioproc *io; Conn *c; SSHChan *sc; int i, n, xconn, fnum; r = a; fnum = (uintptr)r->fid->file->aux; xconn = (fnum >> CONNSHIFT) & ConnMask; c = connections[xconn]; if (c == nil) { respond(r, "Invalid connection"); threadexits(nil); } if (c->state == Closed || c->state == Closing) { r->aux = 0; respond(r, "listen on a closed connection"); threadexits(nil); } sc = c->chans[fnum & ConnMask]; qlock(&c->l); sc->lreq = r; for (i = 0; i < c->nchan; ++i) if (c->chans[i] && c->chans[i]->state == Opening && c->chans[i]->ann && strcmp(c->chans[i]->ann, sc->ann) == 0) break; if (i >= c->nchan) { sc->state = Listening; rsleep(&sc->r); i = sc->waker; if (i < 0) { qunlock(&c->l); r->aux = 0; responderror(r); threadexits(nil); } } else rwakeup(&c->chans[i]->r); qunlock(&c->l); if (c->state == Closed || c->state == Closing || c->state == Eof) { r->aux = 0; respond(r, "Listen on a closed connection"); threadexits(nil); } c->chans[i]->state = Established; p2 = new_packet(c); c->chans[i]->rwindow = 32*1024; add_byte(p2, SSH_MSG_CHANNEL_OPEN_CONFIRMATION); hnputl(p2->payload + 1, c->chans[i]->otherid); hnputl(p2->payload + 5, c->chans[i]->id); hnputl(p2->payload + 9, 32*1024); hnputl(p2->payload + 13, 8192); p2->rlength = 18; n = finish_packet(p2); filedup(r, c->chans[i]->ctl); io = ioproc(); n = iowrite(io, c->datafd, p2->nlength, n); free(p2); closeioproc(io); if (debug) fprint(2, "*** Responding to chan listen open ***\n"); r->aux = 0; if (n < 0) responderror(r); else respond(r, nil); threadexits(nil); } void getdata(Conn *c, SSHChan *sc, Req *r) { Packet *p; Plist *d; int n; n = r->ifcall.count; if (sc->dataq->rem < n) n = sc->dataq->rem; if (n > 8192) n = 8192; r->ifcall.offset = 0; readbuf(r, sc->dataq->st, n); sc->dataq->st += n; sc->dataq->rem -= n; sc->inrqueue -= n; if (sc->dataq->rem <= 0) { d = sc->dataq; sc->dataq = sc->dataq->next; if (d->pack->tlength > sc->rwindow) sc->rwindow = 0; else sc->rwindow -= d->pack->tlength; free(d->pack); free(d); } if (sc->rwindow < 16*1024) { sc->rwindow += 32*1024; if (debug) fprint(2, "Increasing receive window to %lud, inq %lud\n", sc->rwindow, sc->inrqueue); p = new_packet(c); add_byte(p, SSH_MSG_CHANNEL_WINDOW_ADJUST); hnputl(p->payload+1, sc->otherid); hnputl(p->payload+5, 32*1024); p->rlength += 8; n = finish_packet(p); iowrite(c->dio, c->datafd, p->nlength, n); free(p); } r->aux = 0; respond(r, nil); } void stread(Req *r) { Conn *c; SSHChan *sc; int fd, n, lev, cnum, xconn, fnum; char buf[256], path[40]; fnum = (uintptr)r->fid->file->aux;