2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
44 * These functions support the macros and help fiddle mbuf chains for
45 * the nfs op functions. They do things like create the rpc header and
46 * copy data between mbuf chains and uio lists.
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
55 #include <sys/mount.h>
56 #include <sys/vnode.h>
57 #include <sys/namei.h>
59 #include <sys/socket.h>
61 #include <sys/malloc.h>
62 #include <sys/module.h>
63 #include <sys/sysent.h>
64 #include <sys/syscall.h>
65 #include <sys/sysproto.h>
68 #include <vm/vm_object.h>
69 #include <vm/vm_extern.h>
70 #include <vm/vm_zone.h>
72 #include <nfs/rpcv2.h>
73 #include <nfs/nfsproto.h>
74 #include <nfsserver/nfs.h>
75 #include <nfs/xdr_subs.h>
76 #include <nfsserver/nfsm_subs.h>
78 #include <netinet/in.h>
81 * Data items converted to xdr at startup, since they are constant
82 * This is kinda hokey, but may save a little time doing byte swaps
84 u_int32_t nfsrv_nfs_xdrneg1;
85 u_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply,
86 nfsrv_rpc_msgdenied, nfsrv_rpc_autherr,
87 nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted;
88 u_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
90 /* And other global data */
91 static nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
92 NFNON, NFCHR, NFNON };
93 #define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))])
94 #define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS)
98 struct nfssvc_sockhead nfssvc_sockhead;
99 int nfssvc_sockhead_flag;
100 struct nfsd_head nfsd_head;
103 static int nfs_prev_nfssvc_sy_narg;
104 static sy_call_t *nfs_prev_nfssvc_sy_call;
107 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
109 int nfsrv_nfsv3_procid[NFS_NPROCS] = {
136 * and the reverse mapping from generic to Version 2 procedure numbers
138 int nfsrvv2_procid[NFS_NPROCS] = {
165 * Maps errno values to nfs error numbers.
166 * Use NFSERR_IO as the catch all for ones not specifically defined in
169 static u_char nfsrv_v2errmap[ELAST] = {
170 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
171 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
172 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
173 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
174 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
175 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
176 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
177 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
178 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
179 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
180 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
181 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
182 NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
183 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
184 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
185 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
186 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
187 NFSERR_IO /* << Last is 86 */
191 * Maps errno values to nfs error numbers.
192 * Although it is not obvious whether or not NFS clients really care if
193 * a returned error value is in the specified list for the procedure, the
194 * safest thing to do is filter them appropriately. For Version 2, the
195 * X/Open XNFS document is the only specification that defines error values
196 * for each RPC (The RFC simply lists all possible error values for all RPCs),
197 * so I have decided to not do this for Version 2.
198 * The first entry is the default error return and the rest are the valid
199 * errors for that RPC in increasing numeric order.
201 static short nfsv3err_null[] = {
206 static short nfsv3err_getattr[] = {
215 static short nfsv3err_setattr[] = {
231 static short nfsv3err_lookup[] = {
244 static short nfsv3err_access[] = {
253 static short nfsv3err_readlink[] = {
265 static short nfsv3err_read[] = {
277 static short nfsv3err_write[] = {
292 static short nfsv3err_create[] = {
309 static short nfsv3err_mkdir[] = {
326 static short nfsv3err_symlink[] = {
343 static short nfsv3err_mknod[] = {
361 static short nfsv3err_remove[] = {
375 static short nfsv3err_rmdir[] = {
393 static short nfsv3err_rename[] = {
416 static short nfsv3err_link[] = {
436 static short nfsv3err_readdir[] = {
449 static short nfsv3err_readdirplus[] = {
463 static short nfsv3err_fsstat[] = {
472 static short nfsv3err_fsinfo[] = {
480 static short nfsv3err_pathconf[] = {
488 static short nfsv3err_commit[] = {
497 static short *nfsrv_v3errmap[] = {
515 nfsv3err_readdirplus,
523 * Called once to initialize data structures...
526 nfsrv_modevent(module_t mod, int type, void *data)
531 nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
532 nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
533 nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
534 nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
535 nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
536 nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
537 nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR);
538 nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
539 nfsrv_nfs_prog = txdr_unsigned(NFS_PROG);
540 nfsrv_nfs_true = txdr_unsigned(TRUE);
541 nfsrv_nfs_false = txdr_unsigned(FALSE);
542 nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
543 nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
547 nfsrv_init(0); /* Init server data structures */
548 nfsrv_initcache(); /* Init the server request cache */
552 nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
553 sysent[SYS_nfssvc].sy_narg = 2;
554 nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
555 sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
560 untimeout(nfsrv_timer, (void *)NULL, nfsrv_timer_handle);
561 sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
562 sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
567 static moduledata_t nfsserver_mod = {
572 DECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
574 /* So that loader and kldload(2) can find us, wherever we are.. */
575 MODULE_VERSION(nfsserver, 1);
578 * Set up nameidata for a lookup() call and do it.
580 * If pubflag is set, this call is done for a lookup operation on the
581 * public filehandle. In that case we allow crossing mountpoints and
582 * absolute pathnames. However, the caller is expected to check that
583 * the lookup result is within the public fs, and deny access if
586 * nfs_namei() clears out garbage fields that namei() might leave garbage.
587 * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
588 * error occurs but the parent was not requested.
590 * dirp may be set whether an error is returned or not, and must be
591 * released by the caller.
594 nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
595 struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp,
596 caddr_t *dposp, struct vnode **retdirp, struct thread *td, int pubflag)
600 char *fromcp, *tocp, *cp;
604 int error, rdonly, linklen;
605 struct componentname *cnp = &ndp->ni_cnd;
607 *retdirp = (struct vnode *)0;
608 cnp->cn_pnbuf = zalloc(namei_zone);
611 * Copy the name from the mbuf list to ndp->ni_pnbuf
612 * and set the various ndp fields appropriately.
615 tocp = cnp->cn_pnbuf;
617 rem = mtod(md, caddr_t) + md->m_len - fromcp;
618 for (i = 0; i < len; i++) {
625 fromcp = mtod(md, caddr_t);
628 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
638 len = nfsm_rndup(len)-len;
642 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
647 * Extract and set starting directory.
649 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
650 nam, &rdonly, pubflag);
653 if (dp->v_type != VDIR) {
660 cnp->cn_flags |= RDONLY;
663 * Set return directory. Reference to dp is implicitly transfered
664 * to the returned pointer
670 * Oh joy. For WebNFS, handle those pesky '%' escapes,
671 * and the 'native path' indicator.
673 cp = zalloc(namei_zone);
674 fromcp = cnp->cn_pnbuf;
676 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
677 switch ((unsigned char)*fromcp) {
678 case WEBNFS_NATIVE_CHAR:
680 * 'Native' path for us is the same
681 * as a path according to the NFS spec,
682 * just skip the escape char.
687 * More may be added in the future, range 0x80-0xff
691 zfree(namei_zone, cp);
696 * Translate the '%' escapes, URL-style.
698 while (*fromcp != '\0') {
699 if (*fromcp == WEBNFS_ESC_CHAR) {
700 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
702 *tocp++ = HEXSTRTOI(fromcp);
707 zfree(namei_zone, cp);
714 zfree(namei_zone, cnp->cn_pnbuf);
718 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
719 ndp->ni_segflg = UIO_SYSSPACE;
722 ndp->ni_rootdir = rootvnode;
724 if (cnp->cn_pnbuf[0] == '/')
727 cnp->cn_flags |= NOCROSSMOUNT;
731 * Initialize for scan, set ni_startdir and bump ref on dp again
732 * becuase lookup() will dereference ni_startdir.
737 ndp->ni_startdir = dp;
740 cnp->cn_nameptr = cnp->cn_pnbuf;
742 * Call lookup() to do the real work. If an error occurs,
743 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
744 * we do not have to dereference anything before returning.
745 * In either case ni_startdir will be dereferenced and NULLed
753 * Check for encountering a symbolic link. Trivial
754 * termination occurs if no symlink encountered.
755 * Note: zfree is safe because error is 0, so we will
756 * not zfree it again when we break.
758 if ((cnp->cn_flags & ISSYMLINK) == 0) {
759 nfsrv_object_create(ndp->ni_vp);
760 if (cnp->cn_flags & (SAVENAME | SAVESTART))
761 cnp->cn_flags |= HASBUF;
763 zfree(namei_zone, cnp->cn_pnbuf);
770 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
771 VOP_UNLOCK(ndp->ni_dvp, 0, td);
777 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
781 if (ndp->ni_pathlen > 1)
782 cp = zalloc(namei_zone);
786 aiov.iov_len = MAXPATHLEN;
787 auio.uio_iov = &aiov;
790 auio.uio_rw = UIO_READ;
791 auio.uio_segflg = UIO_SYSSPACE;
792 auio.uio_td = (struct thread *)0;
793 auio.uio_resid = MAXPATHLEN;
794 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
797 if (ndp->ni_pathlen > 1)
798 zfree(namei_zone, cp);
804 linklen = MAXPATHLEN - auio.uio_resid;
809 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
810 error = ENAMETOOLONG;
815 * Adjust or replace path
817 if (ndp->ni_pathlen > 1) {
818 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
819 zfree(namei_zone, cnp->cn_pnbuf);
822 cnp->cn_pnbuf[linklen] = '\0';
823 ndp->ni_pathlen += linklen;
826 * Cleanup refs for next loop and check if root directory
827 * should replace current directory. Normally ni_dvp
828 * becomes the new base directory and is cleaned up when
829 * we loop. Explicitly null pointers after invalidation
830 * to clarify operation.
835 if (cnp->cn_pnbuf[0] == '/') {
837 ndp->ni_dvp = ndp->ni_rootdir;
840 ndp->ni_startdir = ndp->ni_dvp;
845 * nfs_namei() guarentees that fields will not contain garbage
846 * whether an error occurs or not. This allows the caller to track
847 * cleanup state trivially.
851 zfree(namei_zone, cnp->cn_pnbuf);
854 ndp->ni_startdir = NULL;
855 cnp->cn_flags &= ~HASBUF;
856 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
863 * A fiddled version of m_adj() that ensures null fill to a long
864 * boundary and only trims off the back end
867 nfsm_adj(struct mbuf *mp, int len, int nul)
874 * Trim from tail. Scan the mbuf chain,
875 * calculating its length and finding the last mbuf.
876 * If the adjustment only affects this mbuf, then just
877 * adjust and return. Otherwise, rescan and truncate
878 * after the remaining size.
884 if (m->m_next == (struct mbuf *)0)
888 if (m->m_len > len) {
891 cp = mtod(m, caddr_t)+m->m_len-nul;
892 for (i = 0; i < nul; i++)
901 * Correct length for chain is "count".
902 * Find the mbuf with last data, adjust its length,
903 * and toss data from remaining mbufs on chain.
905 for (m = mp; m; m = m->m_next) {
906 if (m->m_len >= count) {
909 cp = mtod(m, caddr_t)+m->m_len-nul;
910 for (i = 0; i < nul; i++)
917 for (m = m->m_next;m;m = m->m_next)
922 * Make these functions instead of macros, so that the kernel text size
923 * doesn't get too big...
926 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
927 struct vattr *before_vap, int after_ret, struct vattr *after_vap,
928 struct mbuf **mbp, char **bposp)
930 struct mbuf *mb = *mbp;
935 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
936 *tl = nfsrv_nfs_false;
938 tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
939 *tl++ = nfsrv_nfs_true;
940 txdr_hyper(before_vap->va_size, tl);
942 txdr_nfsv3time(&(before_vap->va_mtime), tl);
944 txdr_nfsv3time(&(before_vap->va_ctime), tl);
948 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
952 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
953 struct vattr *after_vap, struct mbuf **mbp, char **bposp)
955 struct mbuf *mb = *mbp;
958 struct nfs_fattr *fp;
961 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
962 *tl = nfsrv_nfs_false;
964 tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
965 *tl++ = nfsrv_nfs_true;
966 fp = (struct nfs_fattr *)tl;
967 nfsm_srvfattr(nfsd, after_vap, fp);
974 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
975 struct nfs_fattr *fp)
978 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
979 fp->fa_uid = txdr_unsigned(vap->va_uid);
980 fp->fa_gid = txdr_unsigned(vap->va_gid);
981 if (nfsd->nd_flag & ND_NFSV3) {
982 fp->fa_type = vtonfsv3_type(vap->va_type);
983 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
984 txdr_hyper(vap->va_size, &fp->fa3_size);
985 txdr_hyper(vap->va_bytes, &fp->fa3_used);
986 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
987 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
988 fp->fa3_fsid.nfsuquad[0] = 0;
989 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
990 fp->fa3_fileid.nfsuquad[0] = 0;
991 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
992 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
993 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
994 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
996 fp->fa_type = vtonfsv2_type(vap->va_type);
997 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
998 fp->fa2_size = txdr_unsigned(vap->va_size);
999 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1000 if (vap->va_type == VFIFO)
1001 fp->fa2_rdev = 0xffffffff;
1003 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1004 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1005 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1006 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1007 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1008 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1009 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1014 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1015 * - look up fsid in mount list (if not found ret error)
1016 * - get vp and export rights by calling VFS_FHTOVP()
1017 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1018 * - if not lockflag unlock it with VOP_UNLOCK()
1021 nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
1022 struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
1023 int *rdonlyp, int pubflag)
1025 struct thread *td = curthread; /* XXX */
1028 struct ucred *credanon;
1030 #ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */
1031 struct sockaddr_int *saddr;
1034 *vpp = (struct vnode *)0;
1036 if (nfs_ispublicfh(fhp)) {
1037 if (!pubflag || !nfs_pub.np_valid)
1039 fhp = &nfs_pub.np_handle;
1042 mp = vfs_getvfs(&fhp->fh_fsid);
1045 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1048 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1051 #ifdef MNT_EXNORESPORT
1052 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1053 saddr = (struct sockaddr_in *)nam;
1054 if (saddr->sin_family == AF_INET &&
1055 ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1058 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1063 * Check/setup credentials.
1065 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1066 cred->cr_uid = credanon->cr_uid;
1067 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1068 cred->cr_groups[i] = credanon->cr_groups[i];
1069 cred->cr_ngroups = i;
1071 if (exflags & MNT_EXRDONLY)
1076 nfsrv_object_create(*vpp);
1079 VOP_UNLOCK(*vpp, 0, td);
1085 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1086 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1087 * transformed this to all zeroes in both cases, so check for it.
1090 nfs_ispublicfh(fhandle_t *fhp)
1092 char *cp = (char *)fhp;
1095 for (i = 0; i < NFSX_V3FH; i++)
1102 * This function compares two net addresses by family and returns TRUE
1103 * if they are the same host.
1104 * If there is any doubt, return FALSE.
1105 * The AF_INET family is handled as a special case so that address mbufs
1106 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1109 netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
1111 struct sockaddr_in *inetaddr;
1115 inetaddr = (struct sockaddr_in *)nam;
1116 if (inetaddr->sin_family == AF_INET &&
1117 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1127 * Map errnos to NFS error numbers. For Version 3 also filter out error
1128 * numbers not specified for the associated procedure.
1131 nfsrv_errmap(struct nfsrv_descript *nd, int err)
1133 short *defaulterrp, *errp;
1135 if (nd->nd_flag & ND_NFSV3) {
1136 if (nd->nd_procnum <= NFSPROC_COMMIT) {
1137 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1141 else if (*errp > err)
1144 return ((int)*defaulterrp);
1146 return (err & 0xffff);
1149 return ((int)nfsrv_v2errmap[err - 1]);
1154 nfsrv_object_create(struct vnode *vp)
1157 if (vp == NULL || vp->v_type != VREG)
1159 return (vfs_object_create(vp, curthread,
1160 curthread ? curthread->td_proc->p_ucred : NULL));
1164 * Sort the group list in increasing numerical order.
1165 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1166 * that used to be here.)
1169 nfsrvw_sort(gid_t *list, int num)
1174 /* Insertion sort. */
1175 for (i = 1; i < num; i++) {
1177 /* find correct slot for value v, moving others up */
1178 for (j = i; --j >= 0 && v < list[j];)
1179 list[j + 1] = list[j];
1185 * copy credentials making sure that the result can be compared with bcmp().
1188 nfsrv_setcred(struct ucred *incred, struct ucred *outcred)
1192 bzero((caddr_t)outcred, sizeof (struct ucred));
1193 outcred->cr_ref = 1;
1194 outcred->cr_uid = incred->cr_uid;
1195 outcred->cr_ngroups = incred->cr_ngroups;
1196 for (i = 0; i < incred->cr_ngroups; i++)
1197 outcred->cr_groups[i] = incred->cr_groups[i];
1198 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1202 * Helper functions for macros.
1206 nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
1211 tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1212 *tl++ = txdr_unsigned(NFSX_V3FH);
1213 bcopy(f, tl, NFSX_V3FH);
1215 tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
1216 bcopy(f, tl, NFSX_V2FH);
1221 nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
1225 tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
1226 *tl++ = nfsrv_nfs_true;
1227 *tl++ = txdr_unsigned(NFSX_V3FH);
1228 bcopy(f, tl, NFSX_V3FH);
1232 nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
1236 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1239 *s = fxdr_unsigned(int32_t, *tl);
1240 if (*s > m || *s <= 0)
1246 nfsm_srvnamesiz_xx(int *s, struct mbuf **md, caddr_t *dpos)
1250 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1253 *s = fxdr_unsigned(int32_t, *tl);
1254 if (*s > NFS_MAXNAMLEN)
1255 return NFSERR_NAMETOL;
1262 nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
1263 char **bp, char **be, caddr_t bpos)
1269 (*mp)->m_len += *bp - bpos;
1270 MGET(nmp, M_TRYWAIT, MT_DATA);
1271 MCLGET(nmp, M_TRYWAIT);
1272 nmp->m_len = NFSMSIZ(nmp);
1273 (*mp)->m_next = nmp;
1275 *bp = mtod(*mp, caddr_t);
1276 *be = *bp + (*mp)->m_len;
1278 *tl = (u_int32_t *)*bp;
1282 nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
1288 if (nfsd->nd_flag & ND_NFSV3) {
1289 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1292 fhlen = fxdr_unsigned(int, *tl);
1293 if (fhlen != 0 && fhlen != NFSX_V3FH)
1299 tl = nfsm_dissect_xx(fhlen, md, dpos);
1302 bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
1304 bzero((caddr_t)(f), NFSX_V3FH);
1310 nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
1314 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1317 if (*tl == nfsrv_nfs_true) {
1318 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1321 (a)->va_mode = nfstov_mode(*tl);
1323 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1326 if (*tl == nfsrv_nfs_true) {
1327 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1330 (a)->va_uid = fxdr_unsigned(uid_t, *tl);
1332 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1335 if (*tl == nfsrv_nfs_true) {
1336 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1339 (a)->va_gid = fxdr_unsigned(gid_t, *tl);
1341 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1344 if (*tl == nfsrv_nfs_true) {
1345 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1348 (a)->va_size = fxdr_hyper(tl);
1350 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1353 switch (fxdr_unsigned(int, *tl)) {
1354 case NFSV3SATTRTIME_TOCLIENT:
1355 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1358 fxdr_nfsv3time(tl, &(a)->va_atime);
1360 case NFSV3SATTRTIME_TOSERVER:
1361 getnanotime(&(a)->va_atime);
1364 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
1367 switch (fxdr_unsigned(int, *tl)) {
1368 case NFSV3SATTRTIME_TOCLIENT:
1369 tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
1372 fxdr_nfsv3time(tl, &(a)->va_mtime);
1374 case NFSV3SATTRTIME_TOSERVER:
1375 getnanotime(&(a)->va_mtime);