| /* |
| * 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); |
| } |
| |