/* * exportfs - Export a plan 9 name space across a network */#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <libsec.h>#define Extern#include "exportfs.h" #define QIDPATH ((1LL<<48)-1)vlong newqid = 0; enum { Encnone, Encssl, Enctls,}; void (*fcalls[])(Fsrpc*) ={ [Tversion] Xversion, [Tauth] Xauth, [Tflush] Xflush, [Tattach] Xattach, [Twalk] Xwalk, [Topen] slave, [Tcreate] Xcreate, [Tclunk] Xclunk, [Tread] slave, [Twrite] slave, [Tremove] Xremove, [Tstat] Xstat, [Twstat] Xwstat,}; /* accounting and debugging counters */int filecnt;int freecnt;int qidcnt;int qfreecnt;int ncollision; int netfd;int srvfd = -1;int nonone = 1;char *filterp;char *ealgs = "rc4_256 sha1";char *aanfilter = "/bin/aan";int encproto = Encnone;static void mksecret(char *, uchar *);static int localread9pmsg(int, void *, uint, ulong *);static char *anstring = "il!*!0";int filter(int, char *); voidusage(void){ fprint(2, "usage: %s [-ads] [-f dbgfile] [-m msize] [-r root] [-S srvfile] [-e 'crypt hash'] [-A announce-string]\n", argv0); fatal("usage");} voidmain(int argc, char **argv){ char buf[ERRMAX], ebuf[ERRMAX]; Fsrpc *r; int n; char *dbfile, *srv, *file; AuthInfo *ai; ulong initial; dbfile = "/tmp/exportdb"; srv = nil; srvfd = -1; ai = nil; ARGBEGIN{ case 'a': /* * We use p9any so we don't have to visit this code again, with the * cost that this code is incompatible with the old world, which * requires p9sk2. (The two differ in who talks first, so compatibility * is awkward.) */ ai = auth_proxy(0, auth_getkey, "proto=p9any role=server"); if(ai == nil) fatal("auth_proxy: %r"); if(nonone && strcmp(ai->cuid, "none") == 0) fatal("exportfs by none disallowed"); if(auth_chuid(ai, nil) < 0) fatal("auth_chuid: %r"); if(newns(ai->cuid, 0) < 0) fatal("newns"); putenv("service", "exportfs"); break; case 'e': ealgs = ARGF(); if(ealgs == nil) usage(); if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) ealgs = nil; break; case 'S': if(srvfd != -1) usage(); file = EARGF(usage()); if((srvfd = open(file, ORDWR)) < 0) sysfatal("open '%s': %r", file); break; case 'd': dbg++; break; case 'f': dbfile = EARGF(usage()); break; case 'F': /* accepted but ignored, for backwards compatibility */ break; case 'm': messagesize = strtoul(EARGF(usage()), nil, 0); break; case 'r': srv = EARGF(usage()); break; case 's': srv = "/"; break; case 'A': anstring = EARGF(usage()); break; default: usage(); }ARGEND USED(argc, argv); if(dbg) { n = create(dbfile, OWRITE|OTRUNC, 0666); dup(n, DFD); close(n); } if(srvfd >= 0 && srv){ fprint(2, "exportfs: -S cannot be used with -r or -s\n"); usage(); } DEBUG(DFD, "exportfs: started\n"); rfork(RFNOTEG); if(messagesize == 0){ messagesize = iounit(netfd); if(messagesize == 0) messagesize = 8192+IOHDRSZ; } Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs);// for(i=0; i<Nr_workbufs; i++)// Workq[i].buf = emallocz(messagesize); fhash = emallocz(sizeof(Fid*)*FHASHSIZE); fmtinstall('F', fcallfmt); /* * Get tree to serve from network connection, * check we can get there and ack the connection */ if(srvfd != -1) { /* do nothing */ } else if(srv) { chdir(srv); DEBUG(DFD, "invoked as server for %s", srv); strncpy(buf, srv, sizeof buf); } else { buf[0] = 0; n = read(0, buf, sizeof(buf)-1); if(n < 0) { errstr(buf, sizeof buf); fprint(0, "read(0): %s", buf); DEBUG(DFD, "read(0): %s", buf); exits(buf); } buf[n] = 0; if(chdir(buf) < 0) { errstr(ebuf, sizeof ebuf); fprint(0, "chdir(%d:\"%s\"): %s", n, buf, ebuf); DEBUG(DFD, "chdir(%d:\"%s\"): %s", n, buf, ebuf); exits(ebuf); } } DEBUG(DFD, "initing root\n"); initroot(); DEBUG(DFD, "exportfs: %s\n", buf); if(srv == nil && srvfd == -1 && write(0, "OK", 2) != 2) fatal("open ack write"); if ((n = readn(netfd, &initial, sizeof(ulong))) < 0) fatal("can't read initial string: %r\n"); assert(n == sizeof(ulong)); if (!strncmp((char *)&initial, "impo", sizeof(ulong))) { char buf[128], *p, *args[3]; // New import. Read import's parameters... initial = 0; p = buf; while (p - buf < sizeof buf) { if ((n = read(netfd, p, 1)) < 0) fatal("can't read impo arguments: %r\n"); if (n == 0) fatal("connection closed while reading arguments\n"); if (*p == '\n') *p = '\0'; if (*p++ == '\0') break; } if (tokenize(buf, args, nelem(args)) != 2) fatal("impo arguments invalid: impo%s...\n", buf); if (!strcmp(args[0], "aan")) filterp = aanfilter; else if (strcmp(args[0], "nofilter")) fatal("import filter argument unsupported: %s\n", args[0]); if (!strcmp(args[1], "ssl")) encproto = Encssl; else if (!strcmp(args[1], "tls")) encproto = Enctls; else if (strcmp(args[1], "clear")) fatal("import encryption proto unsupported: %s\n", args[1]); if (encproto == Enctls) sysfatal("%s: tls has not yet been implemented\n", argv[0]); } if (encproto != Encnone && ealgs && ai) { uchar key[16]; uchar digest[SHA1dlen]; char fromclientsecret[21]; char fromserversecret[21]; int i; memmove(key+4, ai->secret, ai->nsecret); /* exchange random numbers */ srand(truerand()); for(i = 0; i < 4; i++) key[i+12] = rand(); if (initial) fatal("Protocol botch: old import\n"); if(readn(netfd, key, 4) != 4) fatal("can't read key part; %r\n"); if(write(netfd, key+12, 4) != 4) fatal("can't write key part; %r\n"); /* scramble into two secrets */ sha1(key, sizeof(key), digest, nil); mksecret(fromclientsecret, digest); mksecret(fromserversecret, digest+10); if (filterp) netfd = filter(netfd, filterp); switch (encproto) { case Encssl: netfd = pushssl(netfd, ealgs, fromserversecret, fromclientsecret, nil); break; case Enctls: default: fatal("Unsupported encryption protocol\n"); } if(netfd < 0) fatal("can't establish ssl connection: %r"); } else if (filterp) { if (initial) fatal("Protocol botch: don't know how to deal with this\n"); netfd = filter(netfd, filterp); } /* * Start serving file requests from the network */ for(;;) { r = getsbuf(); if(r == 0) fatal("Out of service buffers"); n = localread9pmsg(netfd, r->buf, messagesize, &initial); if(n <= 0) fatal(nil); if(convM2S(r->buf, n, &r->work) == 0) fatal("convM2S format error"); DEBUG(DFD, "%F\n", &r->work); (fcalls[r->work.type])(r); }} // WARNING: Replace this with the original version as soon as all // _old_ imports have been replaced with negotiating imports. Also// cpu relies on this (which needs to be fixed!) -- pb.static intlocalread9pmsg(int fd, void *abuf, uint n, ulong *initial){ int m, len; uchar *buf; buf = abuf; /* read count */ assert(BIT32SZ == sizeof(ulong)); if (*initial) { memcpy(buf, initial, BIT32SZ); *initial = 0; } else { m = readn(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 = readn(fd, buf+BIT32SZ, len); if(m < len) return 0; return BIT32SZ+m;}voidreply(Fcall *r, Fcall *t, char *err){ uchar *data; int n; t->tag = r->tag; t->fid = r->fid; if(err) { t->type = Rerror; t->ename = err; } else t->type = r->type + 1; DEBUG(DFD, "\t%F\n", t); data = malloc(messagesize); /* not mallocz; no need to clear */ if(data == nil) fatal(Enomem); n = convS2M(t, data, messagesize); if(write(netfd, data, n)!=n){syslog(0, "exportfs", "short write: %r"); fatal("mount write");} free(data);} Fid *getfid(int nr){ Fid *f; for(f = fidhash(nr); f; f = f->next) if(f->nr == nr) return f; return 0;} intfreefid(int nr){ Fid *f, **l; char buf[128]; l = &fidhash(nr); for(f = *l; f; f = f->next) { if(f->nr == nr) { if(f->mid) { sprint(buf, "/mnt/exportfs/%d", f->mid); unmount(0, buf); psmap[f->mid] = 0; } if(f->f) { freefile(f->f); f->f = nil; } *l = f->next; f->next = fidfree; fidfree = f; return 1; } l = &f->next; } return 0; } Fid *newfid(int nr){ Fid *new, **l; int i; l = &fidhash(nr); for(new = *l; new; new = new->next) if(new->nr == nr) return 0; if(fidfree == 0) { fidfree = emallocz(sizeof(Fid) * Fidchunk); for(i = 0; i < Fidchunk-1; i++) fidfree[i].next = &fidfree[i+1]; fidfree[Fidchunk-1].next = 0; } new = fidfree; fidfree = new->next; memset(new, 0, sizeof(Fid)); new->next = *l; *l = new; new->nr = nr; new->fid = -1; new->mid = 0; return new; } Fsrpc *getsbuf(void){ static int ap; int look, rounds; Fsrpc *wb; int small_instead_of_fast = 1; if(small_instead_of_fast) ap = 0; /* so we always start looking at the beginning and reuse buffers */ for(rounds = 0; rounds < 10; rounds++) { for(look = 0; look < Nr_workbufs; look++) { if(++ap == Nr_workbufs) ap = 0; if(Workq[ap].busy == 0) break; } if(look == Nr_workbufs){ sleep(10 * rounds); continue; } wb = &Workq[ap]; wb->pid = 0; wb->canint = 0; wb->flushtag = NOTAG; wb->busy = 1; if(wb->buf == nil) /* allocate buffers dynamically to keep size down */ wb->buf = emallocz(messagesize); return wb; } fatal("No more work buffers"); return nil;}Lines 1–500 of 854. Load more
/* * exportfs - Export a plan 9 name space across a network */ #include <u.h> #include <libc.h> #include <auth.h> #include <fcall.h> #include <libsec.h> #define Extern #include "exportfs.h" #define QIDPATH ((1LL<<48)-1) vlong newqid = 0; enum { Encnone, Encssl, Enctls, }; void (*fcalls[])(Fsrpc*) = { [Tversion] Xversion, [Tauth] Xauth, [Tflush] Xflush, [Tattach] Xattach, [Twalk] Xwalk, [Topen] slave, [Tcreate] Xcreate, [Tclunk] Xclunk, [Tread] slave, [Twrite] slave, [Tremove] Xremove, [Tstat] Xstat, [Twstat] Xwstat, }; /* accounting and debugging counters */ int filecnt; int freecnt; int qidcnt; int qfreecnt; int ncollision; int netfd; int srvfd = -1; int nonone = 1; char *filterp; char *ealgs = "rc4_256 sha1"; char *aanfilter = "/bin/aan"; int encproto = Encnone; static void mksecret(char *, uchar *); static int localread9pmsg(int, void *, uint, ulong *); static char *anstring = "il!*!0"; int filter(int, char *); void usage(void) { fprint(2, "usage: %s [-ads] [-f dbgfile] [-m msize] [-r root] [-S srvfile] [-e 'crypt hash'] [-A announce-string]\n", argv0); fatal("usage"); } void main(int argc, char **argv) { char buf[ERRMAX], ebuf[ERRMAX]; Fsrpc *r; int n; char *dbfile, *srv, *file; AuthInfo *ai; ulong initial; dbfile = "/tmp/exportdb"; srv = nil; srvfd = -1; ai = nil; ARGBEGIN{ case 'a': /* * We use p9any so we don't have to visit this code again, with the * cost that this code is incompatible with the old world, which * requires p9sk2. (The two differ in who talks first, so compatibility * is awkward.) */ ai = auth_proxy(0, auth_getkey, "proto=p9any role=server"); if(ai == nil) fatal("auth_proxy: %r"); if(nonone && strcmp(ai->cuid, "none") == 0) fatal("exportfs by none disallowed"); if(auth_chuid(ai, nil) < 0) fatal("auth_chuid: %r"); if(newns(ai->cuid, 0) < 0) fatal("newns"); putenv("service", "exportfs"); break; case 'e': ealgs = ARGF(); if(ealgs == nil) usage(); if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) ealgs = nil; break; case 'S': if(srvfd != -1) usage(); file = EARGF(usage()); if((srvfd = open(file, ORDWR)) < 0) sysfatal("open '%s': %r", file); break; case 'd': dbg++; break; case 'f': dbfile = EARGF(usage()); break; case 'F': /* accepted but ignored, for backwards compatibility */ break; case 'm': messagesize = strtoul(EARGF(usage()), nil, 0); break; case 'r': srv = EARGF(usage()); break; case 's': srv = "/"; break; case 'A': anstring = EARGF(usage()); break; default: usage(); }ARGEND USED(argc, argv); if(dbg) { n = create(dbfile, OWRITE|OTRUNC, 0666); dup(n, DFD); close(n); } if(srvfd >= 0 && srv){ fprint(2, "exportfs: -S cannot be used with -r or -s\n"); usage(); } DEBUG(DFD, "exportfs: started\n"); rfork(RFNOTEG); if(messagesize == 0){ messagesize = iounit(netfd); if(messagesize == 0) messagesize = 8192+IOHDRSZ; } Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs); // for(i=0; i<Nr_workbufs; i++) // Workq[i].buf = emallocz(messagesize); fhash = emallocz(sizeof(Fid*)*FHASHSIZE); fmtinstall('F', fcallfmt); /* * Get tree to serve from network connection, * check we can get there and ack the connection */ if(srvfd != -1) { /* do nothing */ } else if(srv) { chdir(srv); DEBUG(DFD, "invoked as server for %s", srv); strncpy(buf, srv, sizeof buf); } else { buf[0] = 0; n = read(0, buf, sizeof(buf)-1); if(n < 0) { errstr(buf, sizeof buf); fprint(0, "read(0): %s", buf); DEBUG(DFD, "read(0): %s", buf); exits(buf); } buf[n] = 0; if(chdir(buf) < 0) { errstr(ebuf, sizeof ebuf); fprint(0, "chdir(%d:\"%s\"): %s", n, buf, ebuf); DEBUG(DFD, "chdir(%d:\"%s\"): %s", n, buf, ebuf); exits(ebuf); } } DEBUG(DFD, "initing root\n"); initroot(); DEBUG(DFD, "exportfs: %s\n", buf); if(srv == nil && srvfd == -1 && write(0, "OK", 2) != 2) fatal("open ack write"); if ((n = readn(netfd, &initial, sizeof(ulong))) < 0) fatal("can't read initial string: %r\n"); assert(n == sizeof(ulong)); if (!strncmp((char *)&initial, "impo", sizeof(ulong))) { char buf[128], *p, *args[3]; // New import. Read import's parameters... initial = 0; p = buf; while (p - buf < sizeof buf) { if ((n = read(netfd, p, 1)) < 0) fatal("can't read impo arguments: %r\n"); if (n == 0) fatal("connection closed while reading arguments\n"); if (*p == '\n') *p = '\0'; if (*p++ == '\0') break; } if (tokenize(buf, args, nelem(args)) != 2) fatal("impo arguments invalid: impo%s...\n", buf); if (!strcmp(args[0], "aan")) filterp = aanfilter; else if (strcmp(args[0], "nofilter")) fatal("import filter argument unsupported: %s\n", args[0]); if (!strcmp(args[1], "ssl")) encproto = Encssl; else if (!strcmp(args[1], "tls")) encproto = Enctls; else if (strcmp(args[1], "clear")) fatal("import encryption proto unsupported: %s\n", args[1]); if (encproto == Enctls) sysfatal("%s: tls has not yet been implemented\n", argv[0]); } if (encproto != Encnone && ealgs && ai) { uchar key[16]; uchar digest[SHA1dlen]; char fromclientsecret[21]; char fromserversecret[21]; int i; memmove(key+4, ai->secret, ai->nsecret); /* exchange random numbers */ srand(truerand()); for(i = 0; i < 4; i++) key[i+12] = rand(); if (initial) fatal("Protocol botch: old import\n"); if(readn(netfd, key, 4) != 4) fatal("can't read key part; %r\n"); if(write(netfd, key+12, 4) != 4) fatal("can't write key part; %r\n"); /* scramble into two secrets */ sha1(key, sizeof(key), digest, nil); mksecret(fromclientsecret, digest); mksecret(fromserversecret, digest+10); if (filterp) netfd = filter(netfd, filterp); switch (encproto) { case Encssl: netfd = pushssl(netfd, ealgs, fromserversecret, fromclientsecret, nil); break; case Enctls: default: fatal("Unsupported encryption protocol\n"); } if(netfd < 0) fatal("can't establish ssl connection: %r"); } else if (filterp) { if (initial) fatal("Protocol botch: don't know how to deal with this\n"); netfd = filter(netfd, filterp); } /* * Start serving file requests from the network */ for(;;) { r = getsbuf(); if(r == 0) fatal("Out of service buffers"); n = localread9pmsg(netfd, r->buf, messagesize, &initial); if(n <= 0) fatal(nil); if(convM2S(r->buf, n, &r->work) == 0) fatal("convM2S format error"); DEBUG(DFD, "%F\n", &r->work); (fcalls[r->work.type])(r); } } // WARNING: Replace this with the original version as soon as all // _old_ imports have been replaced with negotiating imports. Also // cpu relies on this (which needs to be fixed!) -- pb. static int localread9pmsg(int fd, void *abuf, uint n, ulong *initial) { int m, len; uchar *buf; buf = abuf; /* read count */ assert(BIT32SZ == sizeof(ulong)); if (*initial) { memcpy(buf, initial, BIT32SZ); *initial = 0; } else { m = readn(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 = readn(fd, buf+BIT32SZ, len); if(m < len) return 0; return BIT32SZ+m; } void reply(Fcall *r, Fcall *t, char *err) { uchar *data; int n; t->tag = r->tag; t->fid = r->fid; if(err) { t->type = Rerror; t->ename = err; } else t->type = r->type + 1; DEBUG(DFD, "\t%F\n", t); data = malloc(messagesize); /* not mallocz; no need to clear */ if(data == nil) fatal(Enomem); n = convS2M(t, data, messagesize); if(write(netfd, data, n)!=n) {syslog(0, "exportfs", "short write: %r"); fatal("mount write"); } free(data); } Fid * getfid(int nr) { Fid *f; for(f = fidhash(nr); f; f = f->next) if(f->nr == nr) return f; return 0; } int freefid(int nr) { Fid *f, **l; char buf[128]; l = &fidhash(nr); for(f = *l; f; f = f->next) { if(f->nr == nr) { if(f->mid) { sprint(buf, "/mnt/exportfs/%d", f->mid); unmount(0, buf); psmap[f->mid] = 0; } if(f->f) { freefile(f->f); f->f = nil; } *l = f->next; f->next = fidfree; fidfree = f; return 1; } l = &f->next; } return 0; } Fid * newfid(int nr) { Fid *new, **l; int i; l = &fidhash(nr); for(new = *l; new; new = new->next) if(new->nr == nr) return 0; if(fidfree == 0) { fidfree = emallocz(sizeof(Fid) * Fidchunk); for(i = 0; i < Fidchunk-1; i++) fidfree[i].next = &fidfree[i+1]; fidfree[Fidchunk-1].next = 0; } new = fidfree; fidfree = new->next; memset(new, 0, sizeof(Fid)); new->next = *l; *l = new; new->nr = nr; new->fid = -1; new->mid = 0; return new; } Fsrpc * getsbuf(void) { static int ap; int look, rounds; Fsrpc *wb; int small_instead_of_fast = 1; if(small_instead_of_fast) ap = 0; /* so we always start looking at the beginning and reuse buffers */ for(rounds = 0; rounds < 10; rounds++) { for(look = 0; look < Nr_workbufs; look++) { if(++ap == Nr_workbufs) ap = 0; if(Workq[ap].busy == 0) break; } if(look == Nr_workbufs){ sleep(10 * rounds); continue; } wb = &Workq[ap]; wb->pid = 0; wb->canint = 0; wb->flushtag = NOTAG; wb->busy = 1; if(wb->buf == nil) /* allocate buffers dynamically to keep size down */ wb->buf = emallocz(messagesize); return wb; } fatal("No more work buffers"); return nil; }