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