/* * Copyright (c) 1997-1999 Erez Zadok * Copyright (c) 1989 Jan-Simon Pendry * Copyright (c) 1989 Imperial College of Science, Technology & Medicine * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Jan-Simon Pendry at Imperial College, London. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgment: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * %W% (Berkeley) %G% * * $Id: stubs.c,v 1.3 1999/01/13 23:31:19 ezk Exp $ * * HLFSD was written at Columbia University Computer Science Department, by * Erez Zadok and Alexander Dupuy * It is being distributed under the same terms and conditions as amd does. */ #ifdef HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include /* * STATIC VARIABLES: */ static nfsfattr rootfattr = {NFDIR, 0040555, 2, 0, 0, 512, 512, 0, 1, 0, ROOTID}; static nfsfattr slinkfattr = {NFLNK, 0120777, 1, 0, 0, NFS_MAXPATHLEN, 512, 0, (NFS_MAXPATHLEN + 1) / 512, 0, SLINKID}; /* user name file attributes */ static nfsfattr un_fattr = {NFLNK, 0120777, 1, 0, 0, NFS_MAXPATHLEN, 512, 0, (NFS_MAXPATHLEN + 1) / 512, 0, INVALIDID}; static int getcreds(struct svc_req *, uid_t *, gid_t *); static int started; static am_nfs_fh slink; static am_nfs_fh un_fhandle; /* * GLOBALS: */ am_nfs_fh root; am_nfs_fh *root_fhp = &root; /* initialize NFS file handles for hlfsd */ void hlfsd_init_filehandles(void) { u_int ui; ui = ROOTID; memcpy(root.fh_data, &ui, sizeof(ui)); ui = SLINKID; memcpy(slink.fh_data, &ui, sizeof(ui)); ui = INVALIDID; memcpy(un_fhandle.fh_data, &ui, sizeof(ui)); } voidp nfsproc_null_2_svc(voidp argp, struct svc_req *rqstp) { static char res; return (voidp) &res; } /* compare if two filehandles are equal */ static int eq_fh(const am_nfs_fh *fh1, const am_nfs_fh *fh2) { return (!memcmp((char *) fh1, (char *) fh2, sizeof(am_nfs_fh))); } nfsattrstat * nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) { static nfsattrstat res; uid_t uid = (uid_t) INVALIDID; gid_t gid = (gid_t) INVALIDID; if (!started) { started++; rootfattr.na_ctime = startup; rootfattr.na_mtime = startup; slinkfattr.na_ctime = startup; slinkfattr.na_mtime = startup; un_fattr.na_ctime = startup; un_fattr.na_mtime = startup; } if (eq_fh(argp, &root)) { res.ns_status = NFS_OK; res.ns_u.ns_attr_u = rootfattr; } else if (eq_fh(argp, &slink)) { #ifndef MNT2_NFS_OPT_SYMTTL /* * This code is needed to defeat Solaris 2.4's (and newer) symlink * values cache. It forces the last-modified time of the symlink to be * current. It is not needed if the O/S has an nfs flag to turn off the * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez. */ if (++slinkfattr.na_mtime.nt_useconds == 0) ++slinkfattr.na_mtime.nt_seconds; #endif /* not MNT2_NFS_OPT_SYMTTL */ res.ns_status = NFS_OK; res.ns_u.ns_attr_u = slinkfattr; } else { if (getcreds(rqstp, &uid, &gid) < 0) { res.ns_status = NFSERR_STALE; return &res; } if (gid != hlfs_gid) { res.ns_status = NFSERR_STALE; } else { memset((char *) &uid, 0, sizeof(int)); uid = *(u_int *) argp->fh_data; if (plt_search(uid) != (uid2home_t *) NULL) { res.ns_status = NFS_OK; un_fattr.na_fileid = uid; res.ns_u.ns_attr_u = un_fattr; #ifdef DEBUG dlog("nfs_getattr: successful search for uid=%ld, gid=%ld", (long) uid, (long) gid); #endif /* DEBUG */ } else { /* not found */ res.ns_status = NFSERR_STALE; } } } return &res; } nfsattrstat * nfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp) { static nfsattrstat res = {NFSERR_ROFS}; return &res; } voidp nfsproc_root_2_svc(voidp argp, struct svc_req *rqstp) { static char res; return (voidp) &res; } nfsdiropres * nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) { static nfsdiropres res; int idx; uid_t uid = (uid_t) INVALIDID; gid_t gid = (gid_t) INVALIDID; if (!started) { started++; rootfattr.na_ctime = startup; rootfattr.na_mtime = startup; slinkfattr.na_ctime = startup; slinkfattr.na_mtime = startup; un_fattr.na_ctime = startup; un_fattr.na_mtime = startup; } if (eq_fh(&argp->da_fhandle, &slink)) { res.dr_status = NFSERR_NOTDIR; return &res; } if (eq_fh(&argp->da_fhandle, &root)) { if (argp->da_name[0] == '.' && (argp->da_name[1] == '\0' || (argp->da_name[1] == '.' && argp->da_name[2] == '\0'))) { res.dr_u.dr_drok_u.drok_fhandle = root; res.dr_u.dr_drok_u.drok_attributes = rootfattr; res.dr_status = NFS_OK; return &res; } if (STREQ(argp->da_name, slinkname)) { res.dr_u.dr_drok_u.drok_fhandle = slink; res.dr_u.dr_drok_u.drok_attributes = slinkfattr; res.dr_status = NFS_OK; return &res; } if (getcreds(rqstp, &uid, &gid) < 0 || gid != hlfs_gid) { res.dr_status = NFSERR_NOENT; return &res; } /* if gets here, gid == hlfs_gid */ if ((idx = untab_index(argp->da_name)) < 0) { res.dr_status = NFSERR_NOENT; return &res; } else { /* entry found and gid is permitted */ un_fattr.na_fileid = untab[idx].uid; res.dr_u.dr_drok_u.drok_attributes = un_fattr; memset((char *) &un_fhandle, 0, sizeof(am_nfs_fh)); *(u_int *) un_fhandle.fh_data = (u_int) untab[idx].uid; strncpy((char *) &un_fhandle.fh_data[sizeof(int)], untab[idx].username, sizeof(am_nfs_fh) - sizeof(int)); res.dr_u.dr_drok_u.drok_fhandle = un_fhandle; res.dr_status = NFS_OK; #ifdef DEBUG dlog("nfs_lookup: successful lookup for uid=%ld, gid=%ld: username=%s", (long) uid, (long) gid, untab[idx].username); #endif /* DEBUG */ return &res; } } /* end of "if (eq_fh(argp->dir.data, root.data)) {" */ res.dr_status = NFSERR_STALE; return &res; } static int getcreds(struct svc_req *rp, uid_t *u, gid_t *g) { struct authunix_parms *aup = (struct authunix_parms *) NULL; #ifdef HAVE_RPC_AUTH_DES_H struct authdes_cred *adp; #endif /* HAVE_RPC_AUTH_DES_H */ switch (rp->rq_cred.oa_flavor) { case AUTH_UNIX: aup = (struct authunix_parms *) rp->rq_clntcred; *u = aup->aup_uid; *g = aup->aup_gid; break; #ifdef HAVE_RPC_AUTH_DES_H case AUTH_DES: adp = (struct authdes_cred *) rp->rq_clntcred; *g = INVALIDID; /* some unknown group id */ if (sscanf(adp->adc_fullname.name, "unix.%lu@", (u_long *) u) == 1) break; /* fall through */ #endif /* HAVE_RPC_AUTH_DES_H */ default: *u = *g = INVALIDID; /* just in case */ svcerr_weakauth(nfsxprt); return -1; } return 0; /* everything is ok */ } nfsreadlinkres * nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) { static nfsreadlinkres res; uid_t userid = (uid_t) INVALIDID; gid_t groupid = hlfs_gid + 1; /* anything not hlfs_gid */ int retval = 0; char *path_val = (char *) NULL; char *username; static uid_t last_uid = (uid_t) INVALIDID; if (eq_fh(argp, &root)) { res.rlr_status = NFSERR_ISDIR; } else if (eq_fh(argp, &slink)) { if (getcreds(rqstp, &userid, &groupid) < 0) return (nfsreadlinkres *) NULL; gettimeofday((struct timeval *) &slinkfattr.na_atime, (struct timezone *) 0); res.rlr_status = NFS_OK; if (groupid == hlfs_gid) { res.rlr_u.rlr_data_u = DOTSTRING; } else if (!(res.rlr_u.rlr_data_u = path_val = homedir(userid))) { /* * parent process (fork in homedir()) continues * processing, by getting a NULL returned as a * "special". Child returns result. */ return (nfsreadlinkres *) NULL; } } else { /* check if asked for user mailbox */ if (getcreds(rqstp, &userid, &groupid) < 0) { return (nfsreadlinkres *) NULL; } if (groupid == hlfs_gid) { memset((char *) &userid, 0, sizeof(int)); userid = *(u_int *) argp->fh_data; username = (char *) &argp->fh_data[sizeof(int)]; if (!(res.rlr_u.rlr_data_u = mailbox(userid, username))) return (nfsreadlinkres *) NULL; } else { res.rlr_status = NFSERR_STALE; } } /* print info, but try to avoid repetitions */ if (userid != last_uid) { plog(XLOG_USER, "mailbox for uid=%ld, gid=%ld is %s", (long) userid, (long) groupid, (char *) res.rlr_u.rlr_data_u); last_uid = userid; } /* I don't think will pass this if -D nofork */ if (serverpid == getpid()) return &res; if (!svc_sendreply(nfsxprt, (XDRPROC_T_TYPE) xdr_readlinkres, (SVC_IN_ARG_TYPE) &res)) svcerr_systemerr(nfsxprt); /* * Child exists here. We need to determine which * exist status to return. The exit status * is gathered using wait() and determines * if we returned $HOME/.hlfsspool or $ALTDIR. The parent * needs this info so it can update the lookup table. */ if (path_val && alt_spooldir && STREQ(path_val, alt_spooldir)) retval = 1; /* could not get real home dir (or uid 0 user) */ else retval = 0; #ifdef DEBUG /* * If asked for -D nofork, then must return the value, * NOT exit, or else the main hlfsd server exits. * Bug where is that status information being collected? */ amuDebugNo(D_FORK) return &res; #endif /* DEBUG */ exit(retval); } nfsreadres * nfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp) { static nfsreadres res = {NFSERR_ACCES}; return &res; } voidp nfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp) { static char res; return (voidp) &res; } nfsattrstat * nfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp) { static nfsattrstat res = {NFSERR_ROFS}; return &res; } nfsdiropres * nfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp) { static nfsdiropres res = {NFSERR_ROFS}; return &res; } nfsstat * nfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) { static nfsstat res = {NFSERR_ROFS}; return &res; } nfsstat * nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp) { static nfsstat res = {NFSERR_ROFS}; return &res; } nfsstat * nfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp) { static nfsstat res = {NFSERR_ROFS}; return &res; } nfsstat * nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp) { static nfsstat res = {NFSERR_ROFS}; return &res; } nfsdiropres * nfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp) { static nfsdiropres res = {NFSERR_ROFS}; return &res; } nfsstat * nfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) { static nfsstat res = {NFSERR_ROFS}; return &res; } nfsreaddirres * nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp) { static nfsreaddirres res; static nfsentry slinkent = {SLINKID, 0, {SLINKCOOKIE}}; static nfsentry dotdotent = {ROOTID, "..", {DOTDOTCOOKIE}, &slinkent}; static nfsentry dotent = {ROOTID, ".", {DOTCOOKIE}, &dotdotent}; slinkent.ne_name = slinkname; if (eq_fh(&argp->rda_fhandle, &slink)) { res.rdr_status = NFSERR_NOTDIR; } else if (eq_fh(&argp->rda_fhandle, &root)) { gettimeofday((struct timeval *) &rootfattr.na_atime, (struct timezone *) 0); res.rdr_status = NFS_OK; switch (argp->rda_cookie[0]) { case 0: res.rdr_u.rdr_reply_u.dl_entries = &dotent; break; case DOTCOOKIE: res.rdr_u.rdr_reply_u.dl_entries = &dotdotent; break; case DOTDOTCOOKIE: res.rdr_u.rdr_reply_u.dl_entries = &slinkent; break; case SLINKCOOKIE: res.rdr_u.rdr_reply_u.dl_entries = (nfsentry *) 0; break; } res.rdr_u.rdr_reply_u.dl_eof = TRUE; } else { res.rdr_status = NFSERR_STALE; } return &res; } nfsstatfsres * nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) { static nfsstatfsres res = {NFS_OK}; res.sfr_u.sfr_reply_u.sfrok_tsize = 1024; res.sfr_u.sfr_reply_u.sfrok_bsize = 1024; /* * Some "df" programs automatically assume that file systems * with zero blocks are meta-filesystems served by automounters. */ res.sfr_u.sfr_reply_u.sfrok_blocks = 0; res.sfr_u.sfr_reply_u.sfrok_bfree = 0; res.sfr_u.sfr_reply_u.sfrok_bavail = 0; return &res; }