home *** CD-ROM | disk | FTP | other *** search
- /*
- * dispatch.c This file contains the function dispatch table.
- *
- * Authors: Donald J. Becker, <becker@super.org>
- * Rick Sladkey, <jrs@world.std.com>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * This software maybe be used for any purpose provided
- * the above copyright notice is retained. It is supplied
- * as is, with no warranty expressed or implied.
- */
-
- #include "nfsd.h"
-
- union argument_types argument;
- union result_types result;
- clnt_param *cp;
-
- extern int
- nfsd_nfsproc_null_2(), nfsd_nfsproc_getattr_2(), nfsd_nfsproc_setattr_2(),
- nfsd_nfsproc_root_2(), nfsd_nfsproc_lookup_2(), nfsd_nfsproc_readlink_2(),
- nfsd_nfsproc_read_2(), nfsd_nfsproc_writecache_2(), nfsd_nfsproc_write_2(),
- nfsd_nfsproc_create_2(), nfsd_nfsproc_remove_2(), nfsd_nfsproc_rename_2(),
- nfsd_nfsproc_link_2(), nfsd_nfsproc_symlink_2(), nfsd_nfsproc_mkdir_2(),
- nfsd_nfsproc_rmdir_2(), nfsd_nfsproc_readdir_2(), nfsd_nfsproc_statfs_2();
-
- /* Allow the following to be over-ridden at compile time. */
-
- #ifndef ROOT_UID
- #define ROOT_UID 0 /* Root user's ID. */
- #endif
-
- #ifndef NOBODY_UID
- #define NOBODY_UID ((uid_t) 65534) /* The unprivileged user. */
- #endif
-
- #ifndef NOBODY_GID
- #define NOBODY_GID ((gid_t) 65534) /* The unprivileged group. */
- #endif
-
- uid_t eff_uid = 0; /* Current effective IDs. */
- gid_t eff_gid = 0;
- GETGROUPS_T last_gids[NGRPS]; /* Current supplementary gids. */
- int last_len = -1;
-
- /*
- * This is a dispatch table to simplify error checking,
- * and supply return attributes for NFS functions.
- */
-
- #ifdef __STDC__
- #define CONCAT(a,b) a##b
- #define CONCAT3(a,b,c) a##b##c
- #define STRING(a) #a
- #else
- #define CONCAT(a,b) a/**/b
- #define CONCAT3(a,b,c) a/**/b/**/c
- #define STRING(a) "a"
- #endif
-
- #define table_ent(auth, ro, cred, res_type, arg_type, funct) { \
- auth, ro, cred, sizeof(res_type), sizeof(arg_type), \
- CONCAT(xdr_,res_type), CONCAT(xdr_,arg_type), \
- CONCAT3(nfsd_nfsproc_,funct,_2), STRING(funct), \
- CONCAT(pr_,arg_type) \
- }
-
- #define nil char
- #define xdr_nil xdr_void
- #define pr_nil pr_void
- #define pr_char pr_void
-
- struct dispatch_entry {
- int authenticate; /* zero if op perm. to any */
- int read_only; /* zero if op perm. on RO FS */
- int credentials; /* zero if no creditials needed */
- int res_size, arg_size; /* sizeof the res/arg structs */
- bool_t (*xdr_result)();
- bool_t (*xdr_argument)();
- int (*funct)(); /* function handler */
- char *name; /* name of function */
- char *(*log_print)(); /* ptr to debug handler */
- };
-
- static struct dispatch_entry dtable[] = {
- table_ent(0,0,0,nil,nil,null),
- table_ent(1,0,1,attrstat,nfs_fh,getattr),
- table_ent(1,1,1,attrstat,sattrargs,setattr),
- table_ent(0,0,0,nil,nil,root),
- table_ent(1,0,1,diropres,diropargs,lookup),
- table_ent(1,0,1,readlinkres,nfs_fh,readlink),
- table_ent(1,0,1,readres,readargs,read),
- table_ent(0,0,0,nil,nil,writecache),
- table_ent(1,1,1,attrstat,writeargs,write),
- table_ent(1,1,1,diropres,createargs,create),
- table_ent(1,1,1,nfsstat,diropargs,remove),
- table_ent(1,1,1,nfsstat,renameargs,rename),
- table_ent(1,1,1,nfsstat,linkargs,link),
- table_ent(1,1,1,nfsstat,symlinkargs,symlink),
- table_ent(1,1,1,diropres,createargs,mkdir),
- table_ent(1,1,1,nfsstat,diropargs,rmdir),
- table_ent(1,0,1,readdirres,readdirargs,readdir),
- table_ent(1,0,0,statfsres,nfs_fh,statfs),
- };
-
- static _PRO( void set_ids, (struct svc_req *rqstp) );
-
- void nfs_dispatch(rqstp, transp)
- struct svc_req *rqstp;
- SVCXPRT *transp;
- {
- unsigned int proc_index = rqstp->rq_proc;
- struct dispatch_entry *dent;
-
- if (proc_index >= (sizeof(dtable) / sizeof(dtable[0]))) {
- svcerr_noproc(transp);
- return;
- }
- dent = &dtable[proc_index];
-
- memset(&argument, 0, dent->arg_size);
- if (!svc_getargs(transp, dent->xdr_argument, &argument)) {
- svcerr_decode(transp);
- return;
- }
- /* Clear the result structure. */
- memset(&result, 0, dent->res_size);
-
- /* Log the call. */
- log_call(rqstp, dent->name, dent->log_print(&argument));
-
- /* Initialize our variables for determining the attributes of
- the file system in nfsd.c */
- svc_rqstp = rqstp;
- client_authenticate = dent->authenticate;
-
- #ifdef READ_ONLY
- /* Punt a write-type request if we are READ_ONLY. */
- if (dent->read_only) {
- result.nfsstat = NFSERR_ROFS;
- goto report_status;
- }
- #endif
-
- /* Establish the credentials and set the effective user IDs. */
- if (dent->credentials)
- set_ids(rqstp);
-
- /* Do the function call itself. */
- result.nfsstat = (*dent->funct) (&argument);
-
- #ifdef READ_ONLY
- report_status:
- #endif
- dprintf(1, "result: %d\n", result.nfsstat);
-
- if (/* result.nfsstat >= 0 && */ /* nfsstat is unsigned? */
- !svc_sendreply(transp, dent->xdr_result, (caddr_t) & result)) {
- svcerr_systemerr(transp);
- }
- if (!svc_freeargs(transp, dent->xdr_argument, &argument)) {
- dprintf(0, "unable to free RPC arguments, exiting\n");
- exit(1);
- }
- }
-
- static void set_ids(rqstp)
- struct svc_req *rqstp;
- {
- uid_t cred_uid;
- gid_t cred_gid;
- int cred_len;
- GETGROUPS_T *cred_gids;
- GETGROUPS_T fake_gid;
-
- if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
- struct authunix_parms *unix_cred;
-
- unix_cred = (struct authunix_parms *) rqstp->rq_clntcred;
- cred_uid = unix_cred->aup_uid;
- cred_gid = unix_cred->aup_gid;
- cred_len = unix_cred->aup_len;
- cred_gids = unix_cred->aup_gids;
- } else {
- cred_uid = NOBODY_UID;
- cred_gid = NOBODY_GID;
- /* Construct a list of one gid. */
- cred_len = 1;
- cred_gids = &fake_gid;
- fake_gid = cred_gid;
- }
-
- /* To set any IDs we first need to be root. What a pain. */
-
- /* First set the group ID. */
- if (eff_gid != cred_gid) {
- if (eff_uid != ROOT_UID) {
- if (seteuid(ROOT_UID) < 0)
- dprintf(0, "Unable to seteuid %d: %s\n",
- ROOT_UID, strerror(errno));
- else
- eff_uid = ROOT_UID;
- }
- if (setegid(cred_gid) < 0)
- dprintf(0, "Unable to setegid %d: %s\n",
- cred_gid, strerror(errno));
- else
- eff_gid = cred_gid;
- }
-
- #ifdef HAVE_SETGROUPS
- /* Next set the supplementary group IDs if possible. */
- if (cred_len < 0 || cred_len > NGRPS)
- dprintf(0, "Negative or huge cred_len: %d\n", cred_len);
- else if (cred_len != last_len
- || memcmp(cred_gids, last_gids, last_len*sizeof(gid_t))) {
- if (eff_uid != ROOT_UID) {
- if (seteuid(ROOT_UID) < 0)
- dprintf(0, "Unable to seteuid %d: %s\n",
- ROOT_UID, strerror(errno));
- else
- eff_uid = ROOT_UID;
- }
- if (setgroups(cred_len, cred_gids) < 0)
- dprintf(0, "Unable to setgroups: %s\n",
- strerror(errno));
- else {
- memcpy(last_gids, cred_gids, cred_len*sizeof(gid_t));
- last_len = cred_len;
- }
- }
- #endif /* HAVE_SETGROUPS */
-
- /* Finally, set the user ID. */
- if (eff_uid != cred_uid) {
- if (eff_uid != ROOT_UID && seteuid(ROOT_UID) < 0)
- dprintf(0, "Unable to seteuid %d: %s\n",
- ROOT_UID, strerror(errno));
- if (seteuid(cred_uid) < 0)
- dprintf(0, "Unable to seteuid %d: %s\n",
- cred_uid, strerror(errno));
- else
- eff_uid = cred_uid;
- }
- }
-
-