/* * Simple read-only NFS v3 server. * Runs every request in its own thread. * Expects client to provide the fsxxx routines in nfs3srv.h. */ #include #include #include #include #include #include "nfs3srv.h" static SunStatus authunixunpack(SunRpc *rpc, SunAuthUnix *au) { uchar *p, *ep; SunAuthInfo *ai; ai = &rpc->cred; if(ai->flavor != SunAuthSys) return SunAuthTooWeak; p = ai->data; ep = p+ai->ndata; if(sunauthunixunpack(p, ep, &p, au) < 0) return SunGarbageArgs; if(au->uid == 0) au->uid = -1; if(au->gid == 0) au->gid = -1; return SunSuccess; } static int rnull(SunMsg *m) { NfsMount3RNull rx; memset(&rx, 0, sizeof rx); return sunmsgreply(m, &rx.call); } static int rmnt(SunMsg *m) { Nfs3Handle nh; NfsMount3RMnt rx; SunAuthUnix au; int ok; if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess) return sunmsgreplyerror(m, ok); /* ignore file system path and return the dump tree */ memset(&rx, 0, sizeof rx); rx.nauth = 0; rx.status = 0; memset(&nh, 0, sizeof nh); fsgetroot(&nh); rx.handle = nh.h; rx.len = nh.len; return sunmsgreply(m, &rx.call); } static int rumnt(SunMsg *m) { NfsMount3RUmnt rx; /* ignore */ memset(&rx, 0, sizeof rx); return sunmsgreply(m, &rx.call); } static int rumntall(SunMsg *m) { NfsMount3RUmntall rx; /* ignore */ memset(&rx, 0, sizeof rx); return sunmsgreply(m, &rx.call); } static int rexport(SunMsg *m) { NfsMount3RExport rx; /* ignore */ memset(&rx, 0, sizeof rx); rx.count = 0; return sunmsgreply(m, &rx.call); } static void rmount3(void *v) { SunMsg *m; m = v; switch(m->call->type){ default: sunmsgreplyerror(m, SunProcUnavail); case NfsMount3CallTNull: rnull(m); break; case NfsMount3CallTMnt: rmnt(m); break; case NfsMount3CallTDump: rmnt(m); break; case NfsMount3CallTUmnt: rumnt(m); break; case NfsMount3CallTUmntall: rumntall(m); break; case NfsMount3CallTExport: rexport(m); break; } } void mount3proc(void *v) { Channel *c; SunMsg *m; threadsetname("mount1"); c = v; while((m=recvp(c)) != nil) threadcreate(rmount3, m, SunStackSize); } static int senderror(SunMsg *m, SunCall *rc, Nfs3Status status) { /* knows that status is first field in all replies */ ((Nfs3RGetattr*)rc)->status = status; return sunmsgreply(m, rc); } static int rnull0(SunMsg *m) { Nfs3RNull rx; memset(&rx, 0, sizeof rx); return sunmsgreply(m, &rx.call); } static int rgetattr(SunMsg *m) { Nfs3TGetattr *tx = (Nfs3TGetattr*)m->call; Nfs3RGetattr rx; SunAuthUnix au; int ok; if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess) return sunmsgreplyerror(m, ok); memset(&rx, 0, sizeof rx); rx.status = fsgetattr(&au, &tx->handle, &rx.attr); return sunmsgreply(m, &rx.call); } static int rlookup(SunMsg *m) { Nfs3TLookup *tx = (Nfs3TLookup*)m->call; Nfs3RLookup rx; SunAuthUnix au; int ok; if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess) return sunmsgreplyerror(m, ok); memset(&rx, 0, sizeof rx); rx.status = fsgetattr(&au, &tx->handle, &rx.dirAttr); if(rx.status != Nfs3Ok) return sunmsgreply(m, &rx.call); rx.haveDirAttr = 1; rx.status = fslookup(&au, &tx->handle, tx->name, &rx.handle); if(rx.status != Nfs3Ok) return sunmsgreply(m, &rx.call); rx.status = fsgetattr(&au, &rx.handle, &rx.attr); if(rx.status != Nfs3Ok) return sunmsgreply(m, &rx.call); rx.haveAttr = 1; return sunmsgreply(m, &rx.call); } static int raccess(SunMsg *m) { Nfs3TAccess *tx = (Nfs3TAccess*)m->call; Nfs3RAccess rx; SunAuthUnix au; int ok; if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess) return sunmsgreplyerror(m, ok); memset(&rx, 0, sizeof rx); rx.haveAttr = 1; rx.status = fsaccess(&au, &tx->handle, tx->access, &rx.access, &rx.attr); return sunmsgreply(m, &rx.call); } static int rreadlink(SunMsg *m) { Nfs3RReadlink rx; Nfs3TReadlink *tx = (Nfs3TReadlink*)m->call; SunAuthUnix au; int ok; if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess) return sunmsgreplyerror(m, ok); memset(&rx, 0, sizeof rx); rx.haveAttr = 0; rx.data = nil; rx.status = fsreadlink(&au, &tx->handle, &rx.data); sunmsgreply(m, &rx.call); free(rx.data); return 0; } static int rread(SunMsg *m) { Nfs3TRead *tx = (Nfs3TRead*)m->call; Nfs3RRead rx; SunAuthUnix au; int ok; if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess) return sunmsgreplyerror(m, ok); memset(&rx, 0, sizeof rx); rx.haveAttr = 0; rx.data = nil; rx.status = fsreadfile(&au, &tx->handle, tx->count, tx->offset, &rx.data, &rx.count, &rx.eof); if(rx.status == Nfs3Ok) rx.ndata = rx.count; sunmsgreply(m, &rx.call); free(rx.data); return 0; } static int rreaddir(SunMsg *m) { Nfs3TReadDir *tx = (Nfs3TReadDir*)m->call; Nfs3RReadDir rx; SunAuthUnix au; int ok; if((ok = authunixunpack(&m->rpc, &au)) != SunSuccess) return sunmsgreplyerror(m, ok); memset(&rx, 0, sizeof rx); rx.status = fsreaddir(&au, &tx->handle, tx->count, tx->cookie, &rx.data, &rx.count, &rx.eof); sunmsgreply(m, &rx.call); free(rx.data); return 0; } static int rreaddirplus(SunMsg *m) { Nfs3RReadDirPlus rx; memset(&rx, 0, sizeof rx); rx.status = Nfs3ErrNotSupp; sunmsgreply(m, &rx.call); return 0; } static int rfsstat(SunMsg *m) { Nfs3RFsStat rx; /* just make something up */ memset(&rx, 0, sizeof rx); rx.status = Nfs3Ok; rx.haveAttr = 0; rx.totalBytes = 1000000000; rx.freeBytes = 0; rx.availBytes = 0; rx.totalFiles = 100000; rx.freeFiles = 0; rx.availFiles = 0; rx.invarSec = 0; return sunmsgreply(m, &rx.call); } static int rfsinfo(SunMsg *m) { Nfs3RFsInfo rx; /* just make something up */ memset(&rx, 0, sizeof rx); rx.status = Nfs3Ok; rx.haveAttr = 0; rx.readMax = MaxDataSize; rx.readPref = MaxDataSize; rx.readMult = MaxDataSize; rx.writeMax = MaxDataSize; rx.writePref = MaxDataSize; rx.writeMult = MaxDataSize; rx.readDirPref = MaxDataSize; rx.maxFileSize = 1LL<<60; rx.timePrec.sec = 1; rx.timePrec.nsec = 0; rx.flags = Nfs3FsHomogeneous|Nfs3FsCanSetTime; return sunmsgreply(m, &rx.call); } static int rpathconf(SunMsg *m) { Nfs3RPathconf rx; memset(&rx, 0, sizeof rx); rx.status = Nfs3Ok; rx.haveAttr = 0; rx.maxLink = 1; rx.maxName = 1024; rx.noTrunc = 1; rx.chownRestricted = 0; rx.caseInsensitive = 0; rx.casePreserving = 1; return sunmsgreply(m, &rx.call); } static int rrofs(SunMsg *m) { uchar buf[512]; /* clumsy hack*/ memset(buf, 0, sizeof buf); return senderror(m, (SunCall*)buf, Nfs3ErrRoFs); } static void rnfs3(void *v) { SunMsg *m; m = v; switch(m->call->type){ default: abort(); case Nfs3CallTNull: rnull0(m); break; case Nfs3CallTGetattr: rgetattr(m); break; case Nfs3CallTLookup: rlookup(m); break; case Nfs3CallTAccess: raccess(m); break; case Nfs3CallTReadlink: rreadlink(m); break; case Nfs3CallTRead: rread(m); break; case Nfs3CallTReadDir: rreaddir(m); break; case Nfs3CallTReadDirPlus: rreaddirplus(m); break; case Nfs3CallTFsStat: rfsstat(m); break; case Nfs3CallTFsInfo: rfsinfo(m); break; case Nfs3CallTPathconf: rpathconf(m); break; case Nfs3CallTSetattr: case Nfs3CallTWrite: case Nfs3CallTCreate: case Nfs3CallTMkdir: case Nfs3CallTSymlink: case Nfs3CallTMknod: case Nfs3CallTRemove: case Nfs3CallTRmdir: case Nfs3CallTLink: case Nfs3CallTCommit: rrofs(m); break; } } void nfs3proc(void *v) { Channel *c; SunMsg *m; c = v; threadsetname("nfs3"); while((m = recvp(c)) != nil) threadcreate(rnfs3, m, SunStackSize); }