/*
 * Copyright (c) 1994-1997 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#pragma ident	"@(#)nfs_server.c	1.14	97/06/10 SMI"

/*
 * the code in this file was copied from Brad ... ??
 */

#include	<stdio.h>
#include	<stdlib.h>
#include	<libintl.h>
#include	<rpc/rpc.h>
#include	<rpcsvc/nfs_prot.h>

#include	"vold.h"

int trace = 0;					/* for tracing our NFS code */

extern int	__rpc_get_local_uid(SVCXPRT *trans, uid_t *uid_out);


void
nfs_program_2(rqstp, transp)
	struct svc_req *rqstp;
	SVCXPRT *transp;
{
	extern void		trace_call(u_long, char *);
	extern void		trace_return(u_long, char *);

	union {
		nfs_fh		nfsproc_getattr_2_svc_arg;
		sattrargs	nfsproc_setattr_2_svc_arg;
		diropargs	nfsproc_lookup_2_svc_arg;
		nfs_fh		nfsproc_readlink_2_svc_arg;
#ifndef RPCGEN_CODE_IS_BETTER
		/* in brad's original code */
		readres		nfsproc_read_2_svc_arg;
#else
		/* generated by rpcgen */
		readargs	nfsproc_read_2_svc_arg;
#endif
		writeargs	nfsproc_write_2_svc_arg;
		createargs	nfsproc_create_2_svc_arg;
		diropargs	nfsproc_remove_2_svc_arg;
		renameargs	nfsproc_rename_2_svc_arg;
		linkargs	nfsproc_link_2_svc_arg;
		symlinkargs	nfsproc_symlink_2_svc_arg;
		createargs	nfsproc_mkdir_2_svc_arg;
		diropargs	nfsproc_rmdir_2_svc_arg;
		readdirargs	nfsproc_readdir_2_svc_arg;
		nfs_fh		nfsproc_statfs_2_svc_arg;
	} argument;

	char			*result;
	bool_t			(*xdr_argument)();
	bool_t			(*xdr_result)();
	char			*(*local)();
	uid_t			uid;



	switch (rqstp->rq_proc) {
	case NULLPROC:
		(void) svc_sendreply(transp, xdr_void, (caddr_t)NULL);
		return;

	case NFSPROC_GETATTR:
		xdr_argument = xdr_nfs_fh;
		xdr_result = xdr_attrstat;
		local = (char *(*)()) nfsproc_getattr_2_svc;
		break;

	case NFSPROC_SETATTR:
		xdr_argument = xdr_sattrargs;
		xdr_result = xdr_attrstat;
		local = (char *(*)()) nfsproc_setattr_2_svc;
		break;

	case NFSPROC_ROOT:
		xdr_argument = xdr_void;
		xdr_result = xdr_void;
		local = (char *(*)()) nfsproc_root_2_svc;
		break;

	case NFSPROC_LOOKUP:
		xdr_argument = xdr_diropargs;
		xdr_result = xdr_diropres;
		local = (char *(*)()) nfsproc_lookup_2_svc;
		break;

	case NFSPROC_READLINK:
		xdr_argument = xdr_nfs_fh;
		xdr_result = xdr_readlinkres;
		local = (char *(*)()) nfsproc_readlink_2_svc;
		break;

	case NFSPROC_READ:
		xdr_argument = xdr_readargs;
		xdr_result = xdr_readres;
		local = (char *(*)()) nfsproc_read_2_svc;
		break;

	case NFSPROC_WRITECACHE:
		xdr_argument = xdr_void;
		xdr_result = xdr_void;
		local = (char *(*)()) nfsproc_writecache_2_svc;
		break;

	case NFSPROC_WRITE:
		xdr_argument = xdr_writeargs;
		xdr_result = xdr_attrstat;
		local = (char *(*)()) nfsproc_write_2_svc;
		break;

	case NFSPROC_CREATE:
		xdr_argument = xdr_createargs;
		xdr_result = xdr_diropres;
		local = (char *(*)()) nfsproc_create_2_svc;
		break;

	case NFSPROC_REMOVE:
		xdr_argument = xdr_diropargs;
		xdr_result = xdr_nfsstat;
		local = (char *(*)()) nfsproc_remove_2_svc;
		break;

	case NFSPROC_RENAME:
		xdr_argument = xdr_renameargs;
		xdr_result = xdr_nfsstat;
		local = (char *(*)()) nfsproc_rename_2_svc;
		break;

	case NFSPROC_LINK:
		xdr_argument = xdr_linkargs;
		xdr_result = xdr_nfsstat;
		local = (char *(*)()) nfsproc_link_2_svc;
		break;

	case NFSPROC_SYMLINK:
		xdr_argument = xdr_symlinkargs;
		xdr_result = xdr_nfsstat;
		local = (char *(*)()) nfsproc_symlink_2_svc;
		break;

	case NFSPROC_MKDIR:
		xdr_argument = xdr_createargs;
		xdr_result = xdr_diropres;
		local = (char *(*)()) nfsproc_mkdir_2_svc;
		break;

	case NFSPROC_RMDIR:
		xdr_argument = xdr_diropargs;
		xdr_result = xdr_nfsstat;
		local = (char *(*)()) nfsproc_rmdir_2_svc;
		break;

	case NFSPROC_READDIR:
		xdr_argument = xdr_readdirargs;
		xdr_result = xdr_readdirres;
		local = (char *(*)()) nfsproc_readdir_2_svc;
		break;

	case NFSPROC_STATFS:
		xdr_argument = xdr_nfs_fh;
		xdr_result = xdr_statfsres;
		local = (char *(*)()) nfsproc_statfs_2_svc;
		break;

	default:
		svcerr_noproc(transp);
		return;
	}

	/*
	 * verify that AUTH_LOOPBACK credentials that follow are valid.
	 * if the uid is not root, the credentials cannot be trusted,
	 * so reject the request
	 */
	if ((__rpc_get_local_uid(transp, &uid) < 0) || (uid != 0)) {
		svcerr_auth(transp, AUTH_BADCRED);
		return;
	}

	if (rqstp->rq_cred.oa_flavor != AUTH_LOOPBACK) {
		fatal(gettext("file system mounted improperly, only the \
			AUTH_LOOPBACK credential is supported\n"));
		/*NOTREACHED*/
	}

	(void) memset(&argument, 0, sizeof (argument));
	if (! svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
		svcerr_decode(transp);
		return;
	}
	if (trace) {
		trace_call(rqstp->rq_proc, (char *)&argument);
	}

	result = (*local)(&argument, rqstp);
	if (trace) {
		trace_return(rqstp->rq_proc, result);
	}
	if (!svc_sendreply(transp, xdr_result, (caddr_t)result)) {
		svcerr_systemerr(transp);
	}
	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
		exit(1);
	}
}
