|  | /* | 
|  | * Simple read-only NFS v3 server. | 
|  | * Runs every request in its own thread. | 
|  | * Expects client to provide the fsxxx routines in nfs3srv.h. | 
|  | */ | 
|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <thread.h> | 
|  | #include <sunrpc.h> | 
|  | #include <nfs3.h> | 
|  | #include "nfs3srv.h" | 
|  |  | 
|  | int			insecure = 0; | 
|  |  | 
|  | 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(!insecure){ | 
|  | 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); | 
|  | } | 
|  |  |