ref: a7d243ef71a1b27166c158ba148da2363402f328
dir: /fs.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <fcall.h> #include <9p.h> #include <mp.h> #include <libsec.h> #include "pki.h" enum { Qroot, Qnew, Qvrf, }; #define QTYPE(qpath) ((qpath)&0xf) #define QIDX(qpath) ((qpath)>>4) #define Q(id, type) (((id)<<4)|(type)) char Egreg[] = "really, greg?"; char Ephase[] = "phase error"; char Eproto[] = "protocol error"; char Eimpl[] = "not implemented"; char Enomem[] = "out of memory"; char Enoexist[] = "file does not exist"; char Ewalkf[] = "walk into file"; char Egarble[] = "garbled message"; char Ecrtfmt[] = "unknown certificate format"; char Ecrtcnt[] = "invalid certificate count"; char Ecrtsz[] = "invalid certificate size"; char Ebadcrt[] = "could not parse certificate"; char Ersrc[] = "invalid resource type"; #define Ephase (abort(), "wut") #define Ecrtsz (abort(), "wut") char *srvname = "pki"; char *mntname = "/mnt/pki"; int debug; Vrf **activevrf; int nactivevrf; int activevrfsz; vlong nextqpath; char *phasenames[] = { "Snone", "Srspec", "Scsize", "Scdata", "Saccept", "Sreject", "Serror", }; int xphase(Vrf *v, int phase) { if(debug) fprint(2, "phase: %s → %s\n", phasenames[v->phase], phasenames[phase]); return phase; } int loadcrt(Vrf *v) { CertX509 *c; void *der; int len; der = v->rbuf; len = v->rbufsz; if(v->rfmt == CFpem) if(decodePEM((char*)v->rbuf, "CERTIFICATE", &len, &der) == nil) return -1; if((c = X509decode(der, len)) == nil) return -1; if(v->icert) addcert(v->tab, c, 0); else v->vrf = c; if(v->rbuf != der) free(der); free(v->rbuf); v->rbuf = nil; v->nrbuf = 0; return 0; } int checkchain(CertTab *tab, CertX509 *c, char *name) { if(c == nil) return Sreject; if(strcmp(c->subject, name) != 0) return Sreject; if(vfcert(tab, c) == 0) return Saccept; else return Sreject; } char* certfill(Vrf *v, char *chunk, int nchunk) { if(nchunk < 0 || v->nrbuf + nchunk > v->rbufsz) return Ecrtsz; memcpy(v->rbuf + v->nrbuf, chunk, nchunk); v->nrbuf += nchunk; if(v->nrbuf == v->rbufsz){ v->rbuf[v->rbufsz] = 0; if(loadcrt(v) == -1){ v->phase = xphase(v, Serror); return Ebadcrt; } v->phase = xphase(v, Scsize); } return nil; } char* mkvrf(Fid *fid, Qid *q) { Vrf *v, **a; if(activevrfsz == nactivevrf){ if(activevrfsz > 100) return nil; if((a = realloc(activevrf, (activevrfsz+1) * sizeof(Vrf*))) == nil) return nil; activevrfsz++; activevrf = a; } if((v = mallocz(sizeof(Vrf), 1)) == nil) return Enomem; nextqpath++; q->path = Q(nextqpath, Qvrf); q->vers = 0; q->type = 0; memset(v, 0, sizeof(Vrf)); v->phase = Snone; v->qid = *q; v->cfmt = CFnone; v->ncrt = 0; v->rbuf = nil; v->nrbuf = 0; v->tab = mktab(roottab, 512); fid->aux = v; activevrf[nactivevrf++] = v; incref(v); return nil; } void vrfopen(Vrf *v) { v->phase = xphase(v, Srspec); } char* vrfspec(Req *r) { char *f[3], buf[IOUNIT]; Vrf *v; int nf; v = r->fid->aux; if(v == nil || v->phase != Srspec) return Ephase; memcpy(buf, r->ifcall.data, r->ifcall.count); buf[r->ifcall.count] = 0; nf = tokenize(buf, f, nelem(f)); if(nf != nelem(f)) return Egarble; if(strcmp(f[0], "verify") != 0) return Egarble; if(strcmp(f[1], "host") == 0) v->ntype = CRhost; else return Ecrtfmt; v->name = strdup(f[2]); if(v->name == nil) return Enomem; v->phase = xphase(v, Scsize); r->ofcall.count = r->ifcall.count; return nil; } char* vrfsize(Req *r) { char buf[65], *f[3], *p, *e; int n, nbuf, nf; Vrf *v; v = r->fid->aux; if(v == nil || v->phase != Scsize) return Ephase; nbuf = nelem(buf)-1; if(r->ifcall.count < nbuf) nbuf = r->ifcall.count; for(n = 0; n < nbuf; n++){ buf[n] = r->ifcall.data[n]; if(buf[n] == '\n' || buf[n] == '\0'){ buf[n++] = 0; break; } } buf[n] = 0; if((p = strchr(buf, '\n')) != nil) *p = 0; nf = tokenize(buf, f, nelem(f)); if(nf == 1 && strcmp(f[0], "done") == 0){ v->phase = checkchain(v->tab, v->vrf, v->name); return nil; } if(nf != nelem(f)) return Egarble; if(strcmp(f[0], "cert") == 0 && v->vrf == nil) v->icert = 0; else if(strcmp(f[0], "icert") == 0) v->icert = 1; else return Egarble; if(strcmp(f[1], "pem") == 0) v->rfmt = CFpem; else if(strcmp(f[1], "der") == 0) v->rfmt = CFder; else return Egarble; v->rbufsz = strtol(f[2], &e, 10); if(*e != 0 || v->rbufsz < 0 || v->rbufsz > 1024*1024) return Egarble; if((v->rbuf = malloc(v->rbufsz + 1)) == nil) return Enomem; v->phase = xphase(v, Scdata); e = certfill(v, r->ifcall.data + n, r->ifcall.count - n); if(e == nil) r->ofcall.count = r->ifcall.count; return e; } char* vrfcert(Req *r) { Vrf *v; char *e; v = r->fid->aux; if(v == nil || v->phase != Scdata) return Ephase; e = certfill(v, r->ifcall.data, r->ifcall.count); if(e == nil) r->ofcall.count = r->ifcall.count; return e; } char* vrflookup(char *name, Qid *q) { vlong id, qpath; char *e; int i; id = strtoll(name, &e, 10); if(*e != 0) return nil; qpath = Q(id, Qvrf); for(i = 0; i < nactivevrf; i++){ if(activevrf[i]->qid.path == qpath){ *q = activevrf[i]->qid; return nil; } } return Enoexist; } void vrfdrop(Vrf *v) { int i; for(i = 0; i < nactivevrf; i++) if(v == activevrf[i]) break; assert(i != nactivevrf); activevrf[i] = activevrf[nactivevrf-1]; nactivevrf--; } int qidstat(Dir *d, vlong qpath) { d->uid = estrdup9p("vrf"); d->gid = estrdup9p("vrf"); d->muid = estrdup9p("vrf"); d->mode = 0444; d->atime = 0; d->mtime = 0; switch(QTYPE(qpath)){ case Qroot: d->qid = (Qid){Qroot, 0, QTDIR}; d->name = estrdup9p("/"); break; case Qnew: d->qid = (Qid){Qnew, 0, 0}; d->name = estrdup9p("new"); break; case Qvrf: d->qid = (Qid){qpath, 0, 0}; d->name = smprint("%lld", QIDX(qpath)); break; } return 0; } int rootgen(int i, Dir *d, void *) { if(i == 0) qidstat(d, Qnew); else if(i >= 1 && i <= nactivevrf) qidstat(d, activevrf[i-1]->qid.path); else return -1; return 0; } char* vrfwrite(Vrf *v, Req *r) { switch(v->phase){ case Srspec: return vrfspec(r); break; case Scsize: return vrfsize(r); break; case Scdata: return vrfcert(r); break; default: return Ephase; break; } } char* vrfread(Vrf *v, Req *r) { switch(v->phase){ case Saccept: readstr(r, "accept"); break; case Sreject: readstr(r, "reject"); break; case Serror: return Eproto; break; default: return Ephase; break; } return nil; } void fsattach(Req *r) { r->ofcall.qid = (Qid){Qroot, 0, QTDIR}; r->fid->qid = r->ofcall.qid; r->fid->aux = nil; respond(r, nil); } void fsopen(Req *r) { Vrf *v; if(QTYPE(r->fid->qid.path) == Qvrf){ v = r->fid->aux; v->phase = Srspec; } respond(r, nil); } void fsread(Req *r) { char *e; e = nil; switch(QTYPE(r->fid->qid.path)){ case Qroot: dirread9p(r, rootgen, nil); break; case Qnew: e = Egreg; break; default: e = vrfread(r->fid->aux, r); break; } respond(r, e); } void fswrite(Req *r) { char *e; switch(QTYPE(r->fid->qid.path)){ case Qroot: case Qnew: e = Egreg; break; default: e = vrfwrite(r->fid->aux, r); break; } respond(r, e); } void fsremove(Req *r) { char *e; e = nil; switch(QTYPE(r->fid->qid.path)){ case Qroot: case Qnew: e = Egreg; break; default: break; } respond(r, e); } void fsstat(Req *r) { if(qidstat(&r->d, r->fid->qid.path) == -1) respond(r, Ephase); else respond(r, nil); } char* fswalk1(Fid *fid, char *name, Qid *q) { char *e; e = nil; switch(QTYPE(fid->qid.path)){ case Qroot: if(strcmp(name, "..") == 0) *q = (Qid){Q(0, Qroot), 0, QTDIR}; else if(strcmp(name, "new") == 0) e = mkvrf(fid, q); else e = vrflookup(name, q); break; default: if(strcmp(name, "..") == 0) *q = (Qid){Q(0, Qroot), 0, QTDIR}; else e = Ewalkf; break; } if(e != nil) fid->qid = *q; return e; } char* fsclone(Fid *old, Fid *new) { if(old->aux != nil){ new->aux = old->aux; incref((Vrf*)new->aux); } return nil; } void fsdestroyfid(Fid *f) { if(f->aux != nil && decref((Vrf*)f->aux) == 0) vrfdrop(f->aux); } Srv pkisrv = { .attach = fsattach, .open = fsopen, .read = fsread, .write = fswrite, .remove = fsremove, .stat = fsstat, .walk1 = fswalk1, .clone = fsclone, .destroyfid = fsdestroyfid, }; void usage(void) { fprint(2, "usage: %s [-r root] certs...\n", argv0); exits("usage"); } void main(int argc, char **argv) { roottab = mktab(nil, 512); ARGBEGIN{ case 'n': mntname = EARGF(usage()); break; case 's': srvname = EARGF(usage()); break; case 'r': loadroots(EARGF(usage())); break; case 't': loadthumbs(EARGF(usage())); break; case 'd': if(debug++) chatty9p++; break; default: usage(); break; }ARGEND; postmountsrv(&pkisrv, srvname, mntname, MREPL); }