blob: c3fc780badc27cc1cba4417d25edd7a7db588a55 [file] [log] [blame]
/*
* 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);
}