diff options
author | dfr <dfr@FreeBSD.org> | 1997-07-16 09:06:30 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 1997-07-16 09:06:30 +0000 |
commit | b627718fbd9e30033d07c3277899ab4726ac6b9b (patch) | |
tree | 8e1ab5384b1f019ad8b612a3fc1d51416baf1acd | |
parent | 9b1c747b1bcc658b6cafea5e03c5c0f0b4cbb74f (diff) | |
download | FreeBSD-src-b627718fbd9e30033d07c3277899ab4726ac6b9b.zip FreeBSD-src-b627718fbd9e30033d07c3277899ab4726ac6b9b.tar.gz |
Merge WebNFS changes from NetBSD.
Obtained from: NetBSD
-rw-r--r-- | sys/nfs/nfs.h | 33 | ||||
-rw-r--r-- | sys/nfs/nfs_common.c | 221 | ||||
-rw-r--r-- | sys/nfs/nfs_common.h | 22 | ||||
-rw-r--r-- | sys/nfs/nfs_nqlease.c | 4 | ||||
-rw-r--r-- | sys/nfs/nfs_serv.c | 106 | ||||
-rw-r--r-- | sys/nfs/nfs_subs.c | 221 | ||||
-rw-r--r-- | sys/nfs/nfs_syscalls.c | 5 | ||||
-rw-r--r-- | sys/nfs/nfsm_subs.h | 22 | ||||
-rw-r--r-- | sys/nfsclient/nfs.h | 33 | ||||
-rw-r--r-- | sys/nfsclient/nfs_nfsiod.c | 5 | ||||
-rw-r--r-- | sys/nfsclient/nfs_subs.c | 221 | ||||
-rw-r--r-- | sys/nfsclient/nfsargs.h | 33 | ||||
-rw-r--r-- | sys/nfsclient/nfsm_subs.h | 22 | ||||
-rw-r--r-- | sys/nfsclient/nfsstats.h | 33 | ||||
-rw-r--r-- | sys/nfsserver/nfs.h | 33 | ||||
-rw-r--r-- | sys/nfsserver/nfs_serv.c | 106 | ||||
-rw-r--r-- | sys/nfsserver/nfs_srvsubs.c | 221 | ||||
-rw-r--r-- | sys/nfsserver/nfs_syscalls.c | 5 | ||||
-rw-r--r-- | sys/nfsserver/nfsm_subs.h | 22 | ||||
-rw-r--r-- | sys/nfsserver/nfsrvstats.h | 33 |
20 files changed, 1147 insertions, 254 deletions
diff --git a/sys/nfs/nfs.h b/sys/nfs/nfs.h index 3521dae..528a366 100644 --- a/sys/nfs/nfs.h +++ b/sys/nfs/nfs.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs.h 8.4 (Berkeley) 5/1/95 - * $Id: nfs.h,v 1.27 1997/05/19 14:36:46 dfr Exp $ + * $Id: nfs.h,v 1.28 1997/06/03 17:22:45 dfr Exp $ */ #ifndef _NFS_NFS_H_ @@ -522,6 +522,30 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) +/* + * Defines for WebNFS + */ + +#define WEBNFS_ESC_CHAR '%' +#define WEBNFS_SPECCHAR_START 0x80 + +#define WEBNFS_NATIVE_CHAR 0x80 +/* + * .. + * Possibly more here in the future. + */ + +/* + * Macro for converting escape characters in WebNFS pathnames. + * Should really be in libkern. + */ + +#define HEXTOC(c) \ + ((c) >= 'a' ? ((c) - ('a' - 10)) : \ + ((c) >= 'A' ? ((c) - ('A' - 10)) : ((c) - '0'))) +#define HEXSTRTOI(p) \ + ((HEXTOC(p[0]) << 4) + HEXTOC(p[1])) + #ifdef NFS_DEBUG extern int nfs_debug; @@ -564,7 +588,7 @@ void nfsm_srvpostopattr __P((struct nfsrv_descript *,int,struct vattr *,struct m int netaddr_match __P((int,union nethostaddr *,struct mbuf *)); int nfs_request __P((struct vnode *,struct mbuf *,int,struct proc *,struct ucred *,struct mbuf **,struct mbuf **,caddr_t *)); int nfs_loadattrcache __P((struct vnode **,struct mbuf **,caddr_t *,struct vattr *)); -int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int)); +int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int,int)); void nfsm_adj __P((struct mbuf *,int,int)); int nfsm_mbuftouio __P((struct mbuf **,struct uio *,int,caddr_t *)); void nfsrv_initcache __P((void)); @@ -606,7 +630,10 @@ int nfsrv_create __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **, struct ucred *,struct nfssvc_sock *,struct mbuf *, - int *,int)); + int *,int,int)); +int nfsrv_setpublicfs __P((struct mount *, struct netexport *, + struct export_args *)); +int nfs_ispublicfh __P((fhandle_t *)); int nfsrv_fsinfo __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_getattr __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, diff --git a/sys/nfs/nfs_common.c b/sys/nfs/nfs_common.c index 572ccc2..105bc52 100644 --- a/sys/nfs/nfs_common.c +++ b/sys/nfs/nfs_common.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94 - * $Id: nfs_subs.c,v 1.37 1997/02/22 09:42:41 peter Exp $ + * $Id: nfs_subs.c,v 1.38 1997/04/04 17:49:29 dfr Exp $ */ /* @@ -53,6 +53,7 @@ #include <sys/socket.h> #include <sys/stat.h> #include <sys/malloc.h> +#include <sys/dirent.h> #ifdef VFS_LKM #include <sys/sysent.h> #include <sys/syscall.h> @@ -560,6 +561,8 @@ extern int nfssvc(struct proc *, struct nfssvc_args *, int *); LIST_HEAD(nfsnodehashhead, nfsnode); +int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); + /* * Create the header for an rpc request packet * The hsiz is the size of the rest of the nfs request header. @@ -1412,10 +1415,16 @@ nfs_getattrcache(vp, vaper) #ifndef NFS_NOSERVER /* - * Set up nameidata for a lookup() call and do it + * Set up nameidata for a lookup() call and do it. + * + * If pubflag is set, this call is done for a lookup operation on the + * public filehandle. In that case we allow crossing mountpoints and + * absolute pathnames. However, the caller is expected to check that + * the lookup result is within the public fs, and deny access if + * it is not. */ int -nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) +nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) register struct nameidata *ndp; fhandle_t *fhp; int len; @@ -1425,13 +1434,15 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) caddr_t *dposp; struct vnode **retdirp; struct proc *p; - int kerbflag; + int kerbflag, pubflag; { register int i, rem; register struct mbuf *md; - register char *fromcp, *tocp; + register char *fromcp, *tocp, *cp; + struct iovec aiov; + struct uio auio; struct vnode *dp; - int error, rdonly; + int error, rdonly, linklen; struct componentname *cnp = &ndp->ni_cnd; *retdirp = (struct vnode *)0; @@ -1455,7 +1466,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) fromcp = mtod(md, caddr_t); rem = md->m_len; } - if (*fromcp == '\0' || *fromcp == '/') { + if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { error = EACCES; goto out; } @@ -1473,55 +1484,170 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) else if (error = nfs_adv(mdp, dposp, len, rem)) goto out; } - ndp->ni_pathlen = tocp - cnp->cn_pnbuf; - cnp->cn_nameptr = cnp->cn_pnbuf; + /* * Extract and set starting directory. */ - if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, - nam, &rdonly, kerbflag)) + error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, + nam, &rdonly, kerbflag, pubflag); + if (error) goto out; if (dp->v_type != VDIR) { vrele(dp); error = ENOTDIR; goto out; } + + if (rdonly) + cnp->cn_flags |= RDONLY; + + if (pubflag) { + /* + * Oh joy. For WebNFS, handle those pesky '%' escapes, + * and the 'native path' indicator. + */ + MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + fromcp = cnp->cn_pnbuf; + tocp = cp; + if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { + switch ((unsigned char)*fromcp) { + case WEBNFS_NATIVE_CHAR: + /* + * 'Native' path for us is the same + * as a path according to the NFS spec, + * just skip the escape char. + */ + fromcp++; + break; + /* + * More may be added in the future, range 0x80-0xff + */ + default: + error = EIO; + FREE(cp, M_NAMEI); + goto out; + } + } + /* + * Translate the '%' escapes, URL-style. + */ + while (*fromcp != '\0') { + if (*fromcp == WEBNFS_ESC_CHAR) { + if (fromcp[1] != '\0' && fromcp[2] != '\0') { + fromcp++; + *tocp++ = HEXSTRTOI(fromcp); + fromcp += 2; + continue; + } else { + error = ENOENT; + FREE(cp, M_NAMEI); + goto out; + } + } else + *tocp++ = *fromcp++; + } + *tocp = '\0'; + FREE(cnp->cn_pnbuf, M_NAMEI); + cnp->cn_pnbuf = cp; + } + + ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; + ndp->ni_segflg = UIO_SYSSPACE; + + if (pubflag) { + ndp->ni_rootdir = rootvnode; + ndp->ni_loopcnt = 0; + if (cnp->cn_pnbuf[0] == '/') + dp = rootvnode; + } else { + cnp->cn_flags |= NOCROSSMOUNT; + } + + cnp->cn_proc = p; VREF(dp); - *retdirp = dp; + + for (;;) { + cnp->cn_nameptr = cnp->cn_pnbuf; ndp->ni_startdir = dp; - if (rdonly) - cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); - else - cnp->cn_flags |= NOCROSSMOUNT; /* * And call lookup() to do the real work */ cnp->cn_proc = p; if (error = lookup(ndp)) - goto out; + break; /* * Check for encountering a symbolic link */ - if (cnp->cn_flags & ISSYMLINK) { + if ((cnp->cn_flags & ISSYMLINK) == 0) { + nfsrv_object_create(ndp->ni_vp); + if (cnp->cn_flags & (SAVENAME | SAVESTART)) { + cnp->cn_flags |= HASBUF; + return (0); + } + break; + } else { if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) - vput(ndp->ni_dvp); - else + VOP_UNLOCK(ndp->ni_dvp, 0, p); + if (!pubflag) { vrele(ndp->ni_dvp); - vput(ndp->ni_vp); - ndp->ni_vp = NULL; - error = EINVAL; - goto out; - } - - nfsrv_object_create(ndp->ni_vp); + vput(ndp->ni_vp); + ndp->ni_vp = NULL; + error = EINVAL; + break; + } - /* - * Check for saved name request - */ - if (cnp->cn_flags & (SAVENAME | SAVESTART)) { - cnp->cn_flags |= HASBUF; - return (0); + if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { + error = ELOOP; + break; + } + if (ndp->ni_pathlen > 0) + MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + else + cp = cnp->cn_pnbuf; + aiov.iov_base = cp; + aiov.iov_len = MAXPATHLEN; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = (struct proc *)0; + auio.uio_resid = MAXPATHLEN; + error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); + if (error) { + badlink: + if (ndp->ni_pathlen > 1) + FREE(cp, M_NAMEI); + break; + } + linklen = MAXPATHLEN - auio.uio_resid; + if (linklen == 0) { + error = ENOENT; + goto badlink; + } + if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { + error = ENAMETOOLONG; + goto badlink; + } + if (ndp->ni_pathlen > 1) { + bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); + FREE(cnp->cn_pnbuf, M_NAMEI); + cnp->cn_pnbuf = cp; + } else + cnp->cn_pnbuf[linklen] = '\0'; + ndp->ni_pathlen += linklen; + vput(ndp->ni_vp); + dp = ndp->ni_dvp; + /* + * Check if root directory should replace current directory. + */ + if (cnp->cn_pnbuf[0] == '/') { + vrele(dp); + dp = ndp->ni_rootdir; + VREF(dp); + } } + } out: FREE(cnp->cn_pnbuf, M_NAMEI); return (error); @@ -1700,7 +1826,7 @@ nfsm_srvfattr(nfsd, vap, fp) * - if not lockflag unlock it with VOP_UNLOCK() */ int -nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) +nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) fhandle_t *fhp; int lockflag; struct vnode **vpp; @@ -1709,6 +1835,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) struct mbuf *nam; int *rdonlyp; int kerbflag; + int pubflag; { struct proc *p = curproc; /* XXX */ register struct mount *mp; @@ -1717,6 +1844,13 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) int error, exflags; *vpp = (struct vnode *)0; + + if (nfs_ispublicfh(fhp)) { + if (!pubflag || !nfs_pub.np_valid) + return (ESTALE); + fhp = &nfs_pub.np_handle; + } + mp = vfs_getvfs(&fhp->fh_fsid); if (!mp) return (ESTALE); @@ -1752,6 +1886,25 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) return (0); } + +/* + * WebNFS: check if a filehandle is a public filehandle. For v3, this + * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has + * transformed this to all zeroes in both cases, so check for it. + */ +int +nfs_ispublicfh(fhp) + fhandle_t *fhp; +{ + char *cp = (char *)fhp; + int i; + + for (i = 0; i < NFSX_V3FH; i++) + if (*cp++ != 0) + return (FALSE); + return (TRUE); +} + #endif /* NFS_NOSERVER */ /* * This function compares two net addresses by family and returns TRUE diff --git a/sys/nfs/nfs_common.h b/sys/nfs/nfs_common.h index c2677c8..e33be82 100644 --- a/sys/nfs/nfs_common.h +++ b/sys/nfs/nfs_common.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfsm_subs.h 8.2 (Berkeley) 3/30/95 - * $Id$ + * $Id: nfsm_subs.h,v 1.12 1997/02/22 09:42:48 peter Exp $ */ @@ -363,18 +363,24 @@ struct mbuf *nfsm_rpchead __P((struct ucred *cr, int nmflag, int procid, } } #define nfsm_srvmtofh(f) \ - { if (nfsd->nd_flag & ND_NFSV3) { \ + { int fhlen = NFSX_V3FH; \ + if (nfsd->nd_flag & ND_NFSV3) { \ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ - if (fxdr_unsigned(int, *tl) != NFSX_V3FH) { \ + fhlen = fxdr_unsigned(int, *tl); \ + if (fhlen == 0) { \ + bzero((caddr_t)(f), NFSX_V3FH); \ + } else if (fhlen != NFSX_V3FH) { \ error = EBADRPC; \ nfsm_reply(0); \ } \ } \ - nfsm_dissect(tl, u_long *, NFSX_V3FH); \ - bcopy((caddr_t)tl, (caddr_t)(f), NFSX_V3FH); \ - if ((nfsd->nd_flag & ND_NFSV3) == 0) \ - nfsm_adv(NFSX_V2FH - NFSX_V3FH); \ - } + if (fhlen != 0) { \ + nfsm_dissect(tl, u_long *, NFSX_V3FH); \ + bcopy((caddr_t)tl, (caddr_t)(f), NFSX_V3FH); \ + if ((nfsd->nd_flag & ND_NFSV3) == 0) \ + nfsm_adv(NFSX_V2FH - NFSX_V3FH); \ + } \ + } #define nfsm_clget \ if (bp >= be) { \ diff --git a/sys/nfs/nfs_nqlease.c b/sys/nfs/nfs_nqlease.c index 821d391..173ea6d 100644 --- a/sys/nfs/nfs_nqlease.c +++ b/sys/nfs/nfs_nqlease.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_nqlease.c 8.9 (Berkeley) 5/20/95 - * $Id: nfs_nqlease.c,v 1.24 1997/02/22 09:42:37 peter Exp $ + * $Id: nfs_nqlease.c,v 1.25 1997/06/03 17:22:46 dfr Exp $ */ @@ -751,7 +751,7 @@ nqnfsrv_getlease(nfsd, slp, procp, mrq) flags = fxdr_unsigned(int, *tl++); nfsd->nd_duration = fxdr_unsigned(int, *tl); error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, - (nfsd->nd_flag & ND_KERBAUTH)); + (nfsd->nd_flag & ND_KERBAUTH), TRUE); if (error) nfsm_reply(0); if (rdonly && flags == ND_WRITE) { diff --git a/sys/nfs/nfs_serv.c b/sys/nfs/nfs_serv.c index f393986..e0770ac 100644 --- a/sys/nfs/nfs_serv.c +++ b/sys/nfs/nfs_serv.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_serv.c 8.3 (Berkeley) 1/12/94 - * $Id: nfs_serv.c,v 1.43 1997/06/03 13:56:54 dfr Exp $ + * $Id: nfs_serv.c,v 1.44 1997/06/14 11:19:35 bde Exp $ */ /* @@ -140,7 +140,7 @@ nfsrv3_access(nfsd, slp, procp, mrq) nfsm_srvmtofh(fhp); nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(1, (struct vattr *)0); return (0); @@ -204,7 +204,7 @@ nfsrv_getattr(nfsd, slp, procp, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(0); return (0); } @@ -296,7 +296,7 @@ nfsrv_setattr(nfsd, slp, procp, mrq) * Now that we have all the fields, lets do it. */ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(2 * NFSX_UNSIGNED); nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); return (0); @@ -365,7 +365,7 @@ nfsrv_lookup(nfsd, slp, procp, mrq) caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register struct nfs_fattr *fp; - struct nameidata nd; + struct nameidata nd, ind, *ndp = &nd; struct vnode *vp, *dirp; nfsfh_t nfh; fhandle_t *fhp; @@ -374,7 +374,7 @@ nfsrv_lookup(nfsd, slp, procp, mrq) register long t1; caddr_t bpos; int error = 0, cache, len, dirattr_ret = 1; - int v3 = (nfsd->nd_flag & ND_NFSV3); + int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag; char *cp2; struct mbuf *mb, *mb2, *mreq; struct vattr va, dirattr, *vap = &va; @@ -383,26 +383,72 @@ nfsrv_lookup(nfsd, slp, procp, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvnamesiz(len); + + pubflag = nfs_ispublicfh(fhp); + nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = LOOKUP; nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), pubflag); + + if (!error && pubflag) { + if (nd.ni_vp->v_type == VDIR && nfs_pub.np_index != NULL) { + /* + * Setup call to lookup() to see if we can find + * the index file. Arguably, this doesn't belong + * in a kernel.. Ugh. + */ + ind = nd; + VOP_UNLOCK(nd.ni_vp, 0, procp); + ind.ni_pathlen = strlen(nfs_pub.np_index); + ind.ni_cnd.cn_nameptr = ind.ni_cnd.cn_pnbuf = + nfs_pub.np_index; + ind.ni_startdir = nd.ni_vp; + VREF(ind.ni_startdir); + error = lookup(&ind); + if (!error) { + /* + * Found an index file. Get rid of + * the old references. + */ + if (dirp) + vrele(dirp); + dirp = nd.ni_vp; + vrele(nd.ni_startdir); + ndp = &ind; + } else + error = 0; + } + /* + * If the public filehandle was used, check that this lookup + * didn't result in a filehandle outside the publicly exported + * filesystem. + */ + + if (!error && ndp->ni_vp->v_mount != nfs_pub.np_mount) { + vput(nd.ni_vp); + error = EPERM; + } + } + if (dirp) { if (v3) dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, procp); vrele(dirp); } + if (error) { nfsm_reply(NFSX_POSTOPATTR(v3)); nfsm_srvpostop_attr(dirattr_ret, &dirattr); return (0); } - nqsrv_getl(nd.ni_startdir, ND_READ); - vrele(nd.ni_startdir); + + nqsrv_getl(ndp->ni_startdir, ND_READ); + vrele(ndp->ni_startdir); FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); - vp = nd.ni_vp; + vp = ndp->ni_vp; bzero((caddr_t)fhp, sizeof(nfh)); fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; error = VFS_VPTOFH(vp, &fhp->fh_fid); @@ -491,7 +537,7 @@ nfsrv_readlink(nfsd, slp, procp, mrq) uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_procp = (struct proc *)0; if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { m_freem(mp3); nfsm_reply(2 * NFSX_UNSIGNED); nfsm_srvpostop_attr(1, (struct vattr *)0); @@ -574,7 +620,7 @@ nfsrv_read(nfsd, slp, procp, mrq) } nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd)); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(2 * NFSX_UNSIGNED); nfsm_srvpostop_attr(1, (struct vattr *)0); return (0); @@ -788,7 +834,7 @@ nfsrv_write(nfsd, slp, procp, mrq) return (0); } if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(2 * NFSX_UNSIGNED); nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); return (0); @@ -1066,7 +1112,7 @@ loop1: v3 = (nfsd->nd_flag & ND_NFSV3); forat_ret = aftat_ret = 1; error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp, - nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH)); + nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); if (!error) { if (v3) forat_ret = VOP_GETATTR(vp, &forat, cred, procp); @@ -1342,7 +1388,7 @@ nfsrv_create(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -1574,7 +1620,7 @@ nfsrv_mknod(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); if (error) { @@ -1723,7 +1769,7 @@ nfsrv_remove(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = DELETE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -1822,7 +1868,7 @@ nfsrv_rename(nfsd, slp, procp, mrq) fromnd.ni_cnd.cn_nameiop = DELETE; fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md, - &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (fdirp) { if (v3) fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred, @@ -1848,7 +1894,7 @@ nfsrv_rename(nfsd, slp, procp, mrq) tond.ni_cnd.cn_nameiop = RENAME; tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; error = nfs_namei(&tond, tfhp, len2, slp, nam, &md, - &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (tdirp) { if (v3) tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred, @@ -2014,7 +2060,7 @@ nfsrv_link(nfsd, slp, procp, mrq) nfsm_srvmtofh(dfhp); nfsm_srvnamesiz(len); if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); nfsm_srvpostop_attr(getret, &at); nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); @@ -2028,7 +2074,7 @@ nfsrv_link(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT; error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2122,7 +2168,7 @@ nfsrv_symlink(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2264,7 +2310,7 @@ nfsrv_mkdir(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2377,7 +2423,7 @@ nfsrv_rmdir(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = DELETE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2526,7 +2572,7 @@ nfsrv_readdir(nfsd, slp, procp, mrq) siz = xfer; fullsiz = siz; if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); return (0); @@ -2790,7 +2836,7 @@ nfsrv_readdirplus(nfsd, slp, procp, mrq) siz = xfer; fullsiz = siz; if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); return (0); @@ -3095,7 +3141,7 @@ nfsrv_commit(nfsd, slp, procp, mrq) tl += 2; cnt = fxdr_unsigned(int, *tl); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(2 * NFSX_UNSIGNED); nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); return (0); @@ -3151,7 +3197,7 @@ nfsrv_statfs(nfsd, slp, procp, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); return (0); @@ -3226,7 +3272,7 @@ nfsrv_fsinfo(nfsd, slp, procp, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); return (0); @@ -3297,7 +3343,7 @@ nfsrv_pathconf(nfsd, slp, procp, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); return (0); diff --git a/sys/nfs/nfs_subs.c b/sys/nfs/nfs_subs.c index 572ccc2..105bc52 100644 --- a/sys/nfs/nfs_subs.c +++ b/sys/nfs/nfs_subs.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94 - * $Id: nfs_subs.c,v 1.37 1997/02/22 09:42:41 peter Exp $ + * $Id: nfs_subs.c,v 1.38 1997/04/04 17:49:29 dfr Exp $ */ /* @@ -53,6 +53,7 @@ #include <sys/socket.h> #include <sys/stat.h> #include <sys/malloc.h> +#include <sys/dirent.h> #ifdef VFS_LKM #include <sys/sysent.h> #include <sys/syscall.h> @@ -560,6 +561,8 @@ extern int nfssvc(struct proc *, struct nfssvc_args *, int *); LIST_HEAD(nfsnodehashhead, nfsnode); +int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); + /* * Create the header for an rpc request packet * The hsiz is the size of the rest of the nfs request header. @@ -1412,10 +1415,16 @@ nfs_getattrcache(vp, vaper) #ifndef NFS_NOSERVER /* - * Set up nameidata for a lookup() call and do it + * Set up nameidata for a lookup() call and do it. + * + * If pubflag is set, this call is done for a lookup operation on the + * public filehandle. In that case we allow crossing mountpoints and + * absolute pathnames. However, the caller is expected to check that + * the lookup result is within the public fs, and deny access if + * it is not. */ int -nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) +nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) register struct nameidata *ndp; fhandle_t *fhp; int len; @@ -1425,13 +1434,15 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) caddr_t *dposp; struct vnode **retdirp; struct proc *p; - int kerbflag; + int kerbflag, pubflag; { register int i, rem; register struct mbuf *md; - register char *fromcp, *tocp; + register char *fromcp, *tocp, *cp; + struct iovec aiov; + struct uio auio; struct vnode *dp; - int error, rdonly; + int error, rdonly, linklen; struct componentname *cnp = &ndp->ni_cnd; *retdirp = (struct vnode *)0; @@ -1455,7 +1466,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) fromcp = mtod(md, caddr_t); rem = md->m_len; } - if (*fromcp == '\0' || *fromcp == '/') { + if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { error = EACCES; goto out; } @@ -1473,55 +1484,170 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) else if (error = nfs_adv(mdp, dposp, len, rem)) goto out; } - ndp->ni_pathlen = tocp - cnp->cn_pnbuf; - cnp->cn_nameptr = cnp->cn_pnbuf; + /* * Extract and set starting directory. */ - if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, - nam, &rdonly, kerbflag)) + error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, + nam, &rdonly, kerbflag, pubflag); + if (error) goto out; if (dp->v_type != VDIR) { vrele(dp); error = ENOTDIR; goto out; } + + if (rdonly) + cnp->cn_flags |= RDONLY; + + if (pubflag) { + /* + * Oh joy. For WebNFS, handle those pesky '%' escapes, + * and the 'native path' indicator. + */ + MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + fromcp = cnp->cn_pnbuf; + tocp = cp; + if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { + switch ((unsigned char)*fromcp) { + case WEBNFS_NATIVE_CHAR: + /* + * 'Native' path for us is the same + * as a path according to the NFS spec, + * just skip the escape char. + */ + fromcp++; + break; + /* + * More may be added in the future, range 0x80-0xff + */ + default: + error = EIO; + FREE(cp, M_NAMEI); + goto out; + } + } + /* + * Translate the '%' escapes, URL-style. + */ + while (*fromcp != '\0') { + if (*fromcp == WEBNFS_ESC_CHAR) { + if (fromcp[1] != '\0' && fromcp[2] != '\0') { + fromcp++; + *tocp++ = HEXSTRTOI(fromcp); + fromcp += 2; + continue; + } else { + error = ENOENT; + FREE(cp, M_NAMEI); + goto out; + } + } else + *tocp++ = *fromcp++; + } + *tocp = '\0'; + FREE(cnp->cn_pnbuf, M_NAMEI); + cnp->cn_pnbuf = cp; + } + + ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; + ndp->ni_segflg = UIO_SYSSPACE; + + if (pubflag) { + ndp->ni_rootdir = rootvnode; + ndp->ni_loopcnt = 0; + if (cnp->cn_pnbuf[0] == '/') + dp = rootvnode; + } else { + cnp->cn_flags |= NOCROSSMOUNT; + } + + cnp->cn_proc = p; VREF(dp); - *retdirp = dp; + + for (;;) { + cnp->cn_nameptr = cnp->cn_pnbuf; ndp->ni_startdir = dp; - if (rdonly) - cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); - else - cnp->cn_flags |= NOCROSSMOUNT; /* * And call lookup() to do the real work */ cnp->cn_proc = p; if (error = lookup(ndp)) - goto out; + break; /* * Check for encountering a symbolic link */ - if (cnp->cn_flags & ISSYMLINK) { + if ((cnp->cn_flags & ISSYMLINK) == 0) { + nfsrv_object_create(ndp->ni_vp); + if (cnp->cn_flags & (SAVENAME | SAVESTART)) { + cnp->cn_flags |= HASBUF; + return (0); + } + break; + } else { if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) - vput(ndp->ni_dvp); - else + VOP_UNLOCK(ndp->ni_dvp, 0, p); + if (!pubflag) { vrele(ndp->ni_dvp); - vput(ndp->ni_vp); - ndp->ni_vp = NULL; - error = EINVAL; - goto out; - } - - nfsrv_object_create(ndp->ni_vp); + vput(ndp->ni_vp); + ndp->ni_vp = NULL; + error = EINVAL; + break; + } - /* - * Check for saved name request - */ - if (cnp->cn_flags & (SAVENAME | SAVESTART)) { - cnp->cn_flags |= HASBUF; - return (0); + if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { + error = ELOOP; + break; + } + if (ndp->ni_pathlen > 0) + MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + else + cp = cnp->cn_pnbuf; + aiov.iov_base = cp; + aiov.iov_len = MAXPATHLEN; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = (struct proc *)0; + auio.uio_resid = MAXPATHLEN; + error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); + if (error) { + badlink: + if (ndp->ni_pathlen > 1) + FREE(cp, M_NAMEI); + break; + } + linklen = MAXPATHLEN - auio.uio_resid; + if (linklen == 0) { + error = ENOENT; + goto badlink; + } + if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { + error = ENAMETOOLONG; + goto badlink; + } + if (ndp->ni_pathlen > 1) { + bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); + FREE(cnp->cn_pnbuf, M_NAMEI); + cnp->cn_pnbuf = cp; + } else + cnp->cn_pnbuf[linklen] = '\0'; + ndp->ni_pathlen += linklen; + vput(ndp->ni_vp); + dp = ndp->ni_dvp; + /* + * Check if root directory should replace current directory. + */ + if (cnp->cn_pnbuf[0] == '/') { + vrele(dp); + dp = ndp->ni_rootdir; + VREF(dp); + } } + } out: FREE(cnp->cn_pnbuf, M_NAMEI); return (error); @@ -1700,7 +1826,7 @@ nfsm_srvfattr(nfsd, vap, fp) * - if not lockflag unlock it with VOP_UNLOCK() */ int -nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) +nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) fhandle_t *fhp; int lockflag; struct vnode **vpp; @@ -1709,6 +1835,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) struct mbuf *nam; int *rdonlyp; int kerbflag; + int pubflag; { struct proc *p = curproc; /* XXX */ register struct mount *mp; @@ -1717,6 +1844,13 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) int error, exflags; *vpp = (struct vnode *)0; + + if (nfs_ispublicfh(fhp)) { + if (!pubflag || !nfs_pub.np_valid) + return (ESTALE); + fhp = &nfs_pub.np_handle; + } + mp = vfs_getvfs(&fhp->fh_fsid); if (!mp) return (ESTALE); @@ -1752,6 +1886,25 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) return (0); } + +/* + * WebNFS: check if a filehandle is a public filehandle. For v3, this + * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has + * transformed this to all zeroes in both cases, so check for it. + */ +int +nfs_ispublicfh(fhp) + fhandle_t *fhp; +{ + char *cp = (char *)fhp; + int i; + + for (i = 0; i < NFSX_V3FH; i++) + if (*cp++ != 0) + return (FALSE); + return (TRUE); +} + #endif /* NFS_NOSERVER */ /* * This function compares two net addresses by family and returns TRUE diff --git a/sys/nfs/nfs_syscalls.c b/sys/nfs/nfs_syscalls.c index de07c23..0c46e28 100644 --- a/sys/nfs/nfs_syscalls.c +++ b/sys/nfs/nfs_syscalls.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 - * $Id: nfs_syscalls.c,v 1.24 1997/05/13 17:25:44 dfr Exp $ + * $Id: nfs_syscalls.c,v 1.25 1997/06/25 21:07:26 tegge Exp $ */ #include <sys/param.h> @@ -1129,7 +1129,8 @@ nfsrv_init(terminating) free((caddr_t)slp, M_NFSSVC); } nfsrv_cleancache(); /* And clear out server cache */ - } + } else + nfs_pub.np_valid = 0; TAILQ_INIT(&nfssvc_sockhead); nfssvc_sockhead_flag &= ~SLP_INIT; diff --git a/sys/nfs/nfsm_subs.h b/sys/nfs/nfsm_subs.h index c2677c8..e33be82 100644 --- a/sys/nfs/nfsm_subs.h +++ b/sys/nfs/nfsm_subs.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfsm_subs.h 8.2 (Berkeley) 3/30/95 - * $Id$ + * $Id: nfsm_subs.h,v 1.12 1997/02/22 09:42:48 peter Exp $ */ @@ -363,18 +363,24 @@ struct mbuf *nfsm_rpchead __P((struct ucred *cr, int nmflag, int procid, } } #define nfsm_srvmtofh(f) \ - { if (nfsd->nd_flag & ND_NFSV3) { \ + { int fhlen = NFSX_V3FH; \ + if (nfsd->nd_flag & ND_NFSV3) { \ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ - if (fxdr_unsigned(int, *tl) != NFSX_V3FH) { \ + fhlen = fxdr_unsigned(int, *tl); \ + if (fhlen == 0) { \ + bzero((caddr_t)(f), NFSX_V3FH); \ + } else if (fhlen != NFSX_V3FH) { \ error = EBADRPC; \ nfsm_reply(0); \ } \ } \ - nfsm_dissect(tl, u_long *, NFSX_V3FH); \ - bcopy((caddr_t)tl, (caddr_t)(f), NFSX_V3FH); \ - if ((nfsd->nd_flag & ND_NFSV3) == 0) \ - nfsm_adv(NFSX_V2FH - NFSX_V3FH); \ - } + if (fhlen != 0) { \ + nfsm_dissect(tl, u_long *, NFSX_V3FH); \ + bcopy((caddr_t)tl, (caddr_t)(f), NFSX_V3FH); \ + if ((nfsd->nd_flag & ND_NFSV3) == 0) \ + nfsm_adv(NFSX_V2FH - NFSX_V3FH); \ + } \ + } #define nfsm_clget \ if (bp >= be) { \ diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h index 3521dae..528a366 100644 --- a/sys/nfsclient/nfs.h +++ b/sys/nfsclient/nfs.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs.h 8.4 (Berkeley) 5/1/95 - * $Id: nfs.h,v 1.27 1997/05/19 14:36:46 dfr Exp $ + * $Id: nfs.h,v 1.28 1997/06/03 17:22:45 dfr Exp $ */ #ifndef _NFS_NFS_H_ @@ -522,6 +522,30 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) +/* + * Defines for WebNFS + */ + +#define WEBNFS_ESC_CHAR '%' +#define WEBNFS_SPECCHAR_START 0x80 + +#define WEBNFS_NATIVE_CHAR 0x80 +/* + * .. + * Possibly more here in the future. + */ + +/* + * Macro for converting escape characters in WebNFS pathnames. + * Should really be in libkern. + */ + +#define HEXTOC(c) \ + ((c) >= 'a' ? ((c) - ('a' - 10)) : \ + ((c) >= 'A' ? ((c) - ('A' - 10)) : ((c) - '0'))) +#define HEXSTRTOI(p) \ + ((HEXTOC(p[0]) << 4) + HEXTOC(p[1])) + #ifdef NFS_DEBUG extern int nfs_debug; @@ -564,7 +588,7 @@ void nfsm_srvpostopattr __P((struct nfsrv_descript *,int,struct vattr *,struct m int netaddr_match __P((int,union nethostaddr *,struct mbuf *)); int nfs_request __P((struct vnode *,struct mbuf *,int,struct proc *,struct ucred *,struct mbuf **,struct mbuf **,caddr_t *)); int nfs_loadattrcache __P((struct vnode **,struct mbuf **,caddr_t *,struct vattr *)); -int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int)); +int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int,int)); void nfsm_adj __P((struct mbuf *,int,int)); int nfsm_mbuftouio __P((struct mbuf **,struct uio *,int,caddr_t *)); void nfsrv_initcache __P((void)); @@ -606,7 +630,10 @@ int nfsrv_create __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **, struct ucred *,struct nfssvc_sock *,struct mbuf *, - int *,int)); + int *,int,int)); +int nfsrv_setpublicfs __P((struct mount *, struct netexport *, + struct export_args *)); +int nfs_ispublicfh __P((fhandle_t *)); int nfsrv_fsinfo __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_getattr __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, diff --git a/sys/nfsclient/nfs_nfsiod.c b/sys/nfsclient/nfs_nfsiod.c index de07c23..0c46e28 100644 --- a/sys/nfsclient/nfs_nfsiod.c +++ b/sys/nfsclient/nfs_nfsiod.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 - * $Id: nfs_syscalls.c,v 1.24 1997/05/13 17:25:44 dfr Exp $ + * $Id: nfs_syscalls.c,v 1.25 1997/06/25 21:07:26 tegge Exp $ */ #include <sys/param.h> @@ -1129,7 +1129,8 @@ nfsrv_init(terminating) free((caddr_t)slp, M_NFSSVC); } nfsrv_cleancache(); /* And clear out server cache */ - } + } else + nfs_pub.np_valid = 0; TAILQ_INIT(&nfssvc_sockhead); nfssvc_sockhead_flag &= ~SLP_INIT; diff --git a/sys/nfsclient/nfs_subs.c b/sys/nfsclient/nfs_subs.c index 572ccc2..105bc52 100644 --- a/sys/nfsclient/nfs_subs.c +++ b/sys/nfsclient/nfs_subs.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94 - * $Id: nfs_subs.c,v 1.37 1997/02/22 09:42:41 peter Exp $ + * $Id: nfs_subs.c,v 1.38 1997/04/04 17:49:29 dfr Exp $ */ /* @@ -53,6 +53,7 @@ #include <sys/socket.h> #include <sys/stat.h> #include <sys/malloc.h> +#include <sys/dirent.h> #ifdef VFS_LKM #include <sys/sysent.h> #include <sys/syscall.h> @@ -560,6 +561,8 @@ extern int nfssvc(struct proc *, struct nfssvc_args *, int *); LIST_HEAD(nfsnodehashhead, nfsnode); +int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); + /* * Create the header for an rpc request packet * The hsiz is the size of the rest of the nfs request header. @@ -1412,10 +1415,16 @@ nfs_getattrcache(vp, vaper) #ifndef NFS_NOSERVER /* - * Set up nameidata for a lookup() call and do it + * Set up nameidata for a lookup() call and do it. + * + * If pubflag is set, this call is done for a lookup operation on the + * public filehandle. In that case we allow crossing mountpoints and + * absolute pathnames. However, the caller is expected to check that + * the lookup result is within the public fs, and deny access if + * it is not. */ int -nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) +nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) register struct nameidata *ndp; fhandle_t *fhp; int len; @@ -1425,13 +1434,15 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) caddr_t *dposp; struct vnode **retdirp; struct proc *p; - int kerbflag; + int kerbflag, pubflag; { register int i, rem; register struct mbuf *md; - register char *fromcp, *tocp; + register char *fromcp, *tocp, *cp; + struct iovec aiov; + struct uio auio; struct vnode *dp; - int error, rdonly; + int error, rdonly, linklen; struct componentname *cnp = &ndp->ni_cnd; *retdirp = (struct vnode *)0; @@ -1455,7 +1466,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) fromcp = mtod(md, caddr_t); rem = md->m_len; } - if (*fromcp == '\0' || *fromcp == '/') { + if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { error = EACCES; goto out; } @@ -1473,55 +1484,170 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) else if (error = nfs_adv(mdp, dposp, len, rem)) goto out; } - ndp->ni_pathlen = tocp - cnp->cn_pnbuf; - cnp->cn_nameptr = cnp->cn_pnbuf; + /* * Extract and set starting directory. */ - if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, - nam, &rdonly, kerbflag)) + error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, + nam, &rdonly, kerbflag, pubflag); + if (error) goto out; if (dp->v_type != VDIR) { vrele(dp); error = ENOTDIR; goto out; } + + if (rdonly) + cnp->cn_flags |= RDONLY; + + if (pubflag) { + /* + * Oh joy. For WebNFS, handle those pesky '%' escapes, + * and the 'native path' indicator. + */ + MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + fromcp = cnp->cn_pnbuf; + tocp = cp; + if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { + switch ((unsigned char)*fromcp) { + case WEBNFS_NATIVE_CHAR: + /* + * 'Native' path for us is the same + * as a path according to the NFS spec, + * just skip the escape char. + */ + fromcp++; + break; + /* + * More may be added in the future, range 0x80-0xff + */ + default: + error = EIO; + FREE(cp, M_NAMEI); + goto out; + } + } + /* + * Translate the '%' escapes, URL-style. + */ + while (*fromcp != '\0') { + if (*fromcp == WEBNFS_ESC_CHAR) { + if (fromcp[1] != '\0' && fromcp[2] != '\0') { + fromcp++; + *tocp++ = HEXSTRTOI(fromcp); + fromcp += 2; + continue; + } else { + error = ENOENT; + FREE(cp, M_NAMEI); + goto out; + } + } else + *tocp++ = *fromcp++; + } + *tocp = '\0'; + FREE(cnp->cn_pnbuf, M_NAMEI); + cnp->cn_pnbuf = cp; + } + + ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; + ndp->ni_segflg = UIO_SYSSPACE; + + if (pubflag) { + ndp->ni_rootdir = rootvnode; + ndp->ni_loopcnt = 0; + if (cnp->cn_pnbuf[0] == '/') + dp = rootvnode; + } else { + cnp->cn_flags |= NOCROSSMOUNT; + } + + cnp->cn_proc = p; VREF(dp); - *retdirp = dp; + + for (;;) { + cnp->cn_nameptr = cnp->cn_pnbuf; ndp->ni_startdir = dp; - if (rdonly) - cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); - else - cnp->cn_flags |= NOCROSSMOUNT; /* * And call lookup() to do the real work */ cnp->cn_proc = p; if (error = lookup(ndp)) - goto out; + break; /* * Check for encountering a symbolic link */ - if (cnp->cn_flags & ISSYMLINK) { + if ((cnp->cn_flags & ISSYMLINK) == 0) { + nfsrv_object_create(ndp->ni_vp); + if (cnp->cn_flags & (SAVENAME | SAVESTART)) { + cnp->cn_flags |= HASBUF; + return (0); + } + break; + } else { if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) - vput(ndp->ni_dvp); - else + VOP_UNLOCK(ndp->ni_dvp, 0, p); + if (!pubflag) { vrele(ndp->ni_dvp); - vput(ndp->ni_vp); - ndp->ni_vp = NULL; - error = EINVAL; - goto out; - } - - nfsrv_object_create(ndp->ni_vp); + vput(ndp->ni_vp); + ndp->ni_vp = NULL; + error = EINVAL; + break; + } - /* - * Check for saved name request - */ - if (cnp->cn_flags & (SAVENAME | SAVESTART)) { - cnp->cn_flags |= HASBUF; - return (0); + if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { + error = ELOOP; + break; + } + if (ndp->ni_pathlen > 0) + MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + else + cp = cnp->cn_pnbuf; + aiov.iov_base = cp; + aiov.iov_len = MAXPATHLEN; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = (struct proc *)0; + auio.uio_resid = MAXPATHLEN; + error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); + if (error) { + badlink: + if (ndp->ni_pathlen > 1) + FREE(cp, M_NAMEI); + break; + } + linklen = MAXPATHLEN - auio.uio_resid; + if (linklen == 0) { + error = ENOENT; + goto badlink; + } + if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { + error = ENAMETOOLONG; + goto badlink; + } + if (ndp->ni_pathlen > 1) { + bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); + FREE(cnp->cn_pnbuf, M_NAMEI); + cnp->cn_pnbuf = cp; + } else + cnp->cn_pnbuf[linklen] = '\0'; + ndp->ni_pathlen += linklen; + vput(ndp->ni_vp); + dp = ndp->ni_dvp; + /* + * Check if root directory should replace current directory. + */ + if (cnp->cn_pnbuf[0] == '/') { + vrele(dp); + dp = ndp->ni_rootdir; + VREF(dp); + } } + } out: FREE(cnp->cn_pnbuf, M_NAMEI); return (error); @@ -1700,7 +1826,7 @@ nfsm_srvfattr(nfsd, vap, fp) * - if not lockflag unlock it with VOP_UNLOCK() */ int -nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) +nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) fhandle_t *fhp; int lockflag; struct vnode **vpp; @@ -1709,6 +1835,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) struct mbuf *nam; int *rdonlyp; int kerbflag; + int pubflag; { struct proc *p = curproc; /* XXX */ register struct mount *mp; @@ -1717,6 +1844,13 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) int error, exflags; *vpp = (struct vnode *)0; + + if (nfs_ispublicfh(fhp)) { + if (!pubflag || !nfs_pub.np_valid) + return (ESTALE); + fhp = &nfs_pub.np_handle; + } + mp = vfs_getvfs(&fhp->fh_fsid); if (!mp) return (ESTALE); @@ -1752,6 +1886,25 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) return (0); } + +/* + * WebNFS: check if a filehandle is a public filehandle. For v3, this + * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has + * transformed this to all zeroes in both cases, so check for it. + */ +int +nfs_ispublicfh(fhp) + fhandle_t *fhp; +{ + char *cp = (char *)fhp; + int i; + + for (i = 0; i < NFSX_V3FH; i++) + if (*cp++ != 0) + return (FALSE); + return (TRUE); +} + #endif /* NFS_NOSERVER */ /* * This function compares two net addresses by family and returns TRUE diff --git a/sys/nfsclient/nfsargs.h b/sys/nfsclient/nfsargs.h index 3521dae..528a366 100644 --- a/sys/nfsclient/nfsargs.h +++ b/sys/nfsclient/nfsargs.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs.h 8.4 (Berkeley) 5/1/95 - * $Id: nfs.h,v 1.27 1997/05/19 14:36:46 dfr Exp $ + * $Id: nfs.h,v 1.28 1997/06/03 17:22:45 dfr Exp $ */ #ifndef _NFS_NFS_H_ @@ -522,6 +522,30 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) +/* + * Defines for WebNFS + */ + +#define WEBNFS_ESC_CHAR '%' +#define WEBNFS_SPECCHAR_START 0x80 + +#define WEBNFS_NATIVE_CHAR 0x80 +/* + * .. + * Possibly more here in the future. + */ + +/* + * Macro for converting escape characters in WebNFS pathnames. + * Should really be in libkern. + */ + +#define HEXTOC(c) \ + ((c) >= 'a' ? ((c) - ('a' - 10)) : \ + ((c) >= 'A' ? ((c) - ('A' - 10)) : ((c) - '0'))) +#define HEXSTRTOI(p) \ + ((HEXTOC(p[0]) << 4) + HEXTOC(p[1])) + #ifdef NFS_DEBUG extern int nfs_debug; @@ -564,7 +588,7 @@ void nfsm_srvpostopattr __P((struct nfsrv_descript *,int,struct vattr *,struct m int netaddr_match __P((int,union nethostaddr *,struct mbuf *)); int nfs_request __P((struct vnode *,struct mbuf *,int,struct proc *,struct ucred *,struct mbuf **,struct mbuf **,caddr_t *)); int nfs_loadattrcache __P((struct vnode **,struct mbuf **,caddr_t *,struct vattr *)); -int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int)); +int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int,int)); void nfsm_adj __P((struct mbuf *,int,int)); int nfsm_mbuftouio __P((struct mbuf **,struct uio *,int,caddr_t *)); void nfsrv_initcache __P((void)); @@ -606,7 +630,10 @@ int nfsrv_create __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **, struct ucred *,struct nfssvc_sock *,struct mbuf *, - int *,int)); + int *,int,int)); +int nfsrv_setpublicfs __P((struct mount *, struct netexport *, + struct export_args *)); +int nfs_ispublicfh __P((fhandle_t *)); int nfsrv_fsinfo __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_getattr __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, diff --git a/sys/nfsclient/nfsm_subs.h b/sys/nfsclient/nfsm_subs.h index c2677c8..e33be82 100644 --- a/sys/nfsclient/nfsm_subs.h +++ b/sys/nfsclient/nfsm_subs.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfsm_subs.h 8.2 (Berkeley) 3/30/95 - * $Id$ + * $Id: nfsm_subs.h,v 1.12 1997/02/22 09:42:48 peter Exp $ */ @@ -363,18 +363,24 @@ struct mbuf *nfsm_rpchead __P((struct ucred *cr, int nmflag, int procid, } } #define nfsm_srvmtofh(f) \ - { if (nfsd->nd_flag & ND_NFSV3) { \ + { int fhlen = NFSX_V3FH; \ + if (nfsd->nd_flag & ND_NFSV3) { \ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ - if (fxdr_unsigned(int, *tl) != NFSX_V3FH) { \ + fhlen = fxdr_unsigned(int, *tl); \ + if (fhlen == 0) { \ + bzero((caddr_t)(f), NFSX_V3FH); \ + } else if (fhlen != NFSX_V3FH) { \ error = EBADRPC; \ nfsm_reply(0); \ } \ } \ - nfsm_dissect(tl, u_long *, NFSX_V3FH); \ - bcopy((caddr_t)tl, (caddr_t)(f), NFSX_V3FH); \ - if ((nfsd->nd_flag & ND_NFSV3) == 0) \ - nfsm_adv(NFSX_V2FH - NFSX_V3FH); \ - } + if (fhlen != 0) { \ + nfsm_dissect(tl, u_long *, NFSX_V3FH); \ + bcopy((caddr_t)tl, (caddr_t)(f), NFSX_V3FH); \ + if ((nfsd->nd_flag & ND_NFSV3) == 0) \ + nfsm_adv(NFSX_V2FH - NFSX_V3FH); \ + } \ + } #define nfsm_clget \ if (bp >= be) { \ diff --git a/sys/nfsclient/nfsstats.h b/sys/nfsclient/nfsstats.h index 3521dae..528a366 100644 --- a/sys/nfsclient/nfsstats.h +++ b/sys/nfsclient/nfsstats.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs.h 8.4 (Berkeley) 5/1/95 - * $Id: nfs.h,v 1.27 1997/05/19 14:36:46 dfr Exp $ + * $Id: nfs.h,v 1.28 1997/06/03 17:22:45 dfr Exp $ */ #ifndef _NFS_NFS_H_ @@ -522,6 +522,30 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) +/* + * Defines for WebNFS + */ + +#define WEBNFS_ESC_CHAR '%' +#define WEBNFS_SPECCHAR_START 0x80 + +#define WEBNFS_NATIVE_CHAR 0x80 +/* + * .. + * Possibly more here in the future. + */ + +/* + * Macro for converting escape characters in WebNFS pathnames. + * Should really be in libkern. + */ + +#define HEXTOC(c) \ + ((c) >= 'a' ? ((c) - ('a' - 10)) : \ + ((c) >= 'A' ? ((c) - ('A' - 10)) : ((c) - '0'))) +#define HEXSTRTOI(p) \ + ((HEXTOC(p[0]) << 4) + HEXTOC(p[1])) + #ifdef NFS_DEBUG extern int nfs_debug; @@ -564,7 +588,7 @@ void nfsm_srvpostopattr __P((struct nfsrv_descript *,int,struct vattr *,struct m int netaddr_match __P((int,union nethostaddr *,struct mbuf *)); int nfs_request __P((struct vnode *,struct mbuf *,int,struct proc *,struct ucred *,struct mbuf **,struct mbuf **,caddr_t *)); int nfs_loadattrcache __P((struct vnode **,struct mbuf **,caddr_t *,struct vattr *)); -int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int)); +int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int,int)); void nfsm_adj __P((struct mbuf *,int,int)); int nfsm_mbuftouio __P((struct mbuf **,struct uio *,int,caddr_t *)); void nfsrv_initcache __P((void)); @@ -606,7 +630,10 @@ int nfsrv_create __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **, struct ucred *,struct nfssvc_sock *,struct mbuf *, - int *,int)); + int *,int,int)); +int nfsrv_setpublicfs __P((struct mount *, struct netexport *, + struct export_args *)); +int nfs_ispublicfh __P((fhandle_t *)); int nfsrv_fsinfo __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_getattr __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, diff --git a/sys/nfsserver/nfs.h b/sys/nfsserver/nfs.h index 3521dae..528a366 100644 --- a/sys/nfsserver/nfs.h +++ b/sys/nfsserver/nfs.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs.h 8.4 (Berkeley) 5/1/95 - * $Id: nfs.h,v 1.27 1997/05/19 14:36:46 dfr Exp $ + * $Id: nfs.h,v 1.28 1997/06/03 17:22:45 dfr Exp $ */ #ifndef _NFS_NFS_H_ @@ -522,6 +522,30 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) +/* + * Defines for WebNFS + */ + +#define WEBNFS_ESC_CHAR '%' +#define WEBNFS_SPECCHAR_START 0x80 + +#define WEBNFS_NATIVE_CHAR 0x80 +/* + * .. + * Possibly more here in the future. + */ + +/* + * Macro for converting escape characters in WebNFS pathnames. + * Should really be in libkern. + */ + +#define HEXTOC(c) \ + ((c) >= 'a' ? ((c) - ('a' - 10)) : \ + ((c) >= 'A' ? ((c) - ('A' - 10)) : ((c) - '0'))) +#define HEXSTRTOI(p) \ + ((HEXTOC(p[0]) << 4) + HEXTOC(p[1])) + #ifdef NFS_DEBUG extern int nfs_debug; @@ -564,7 +588,7 @@ void nfsm_srvpostopattr __P((struct nfsrv_descript *,int,struct vattr *,struct m int netaddr_match __P((int,union nethostaddr *,struct mbuf *)); int nfs_request __P((struct vnode *,struct mbuf *,int,struct proc *,struct ucred *,struct mbuf **,struct mbuf **,caddr_t *)); int nfs_loadattrcache __P((struct vnode **,struct mbuf **,caddr_t *,struct vattr *)); -int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int)); +int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int,int)); void nfsm_adj __P((struct mbuf *,int,int)); int nfsm_mbuftouio __P((struct mbuf **,struct uio *,int,caddr_t *)); void nfsrv_initcache __P((void)); @@ -606,7 +630,10 @@ int nfsrv_create __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **, struct ucred *,struct nfssvc_sock *,struct mbuf *, - int *,int)); + int *,int,int)); +int nfsrv_setpublicfs __P((struct mount *, struct netexport *, + struct export_args *)); +int nfs_ispublicfh __P((fhandle_t *)); int nfsrv_fsinfo __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_getattr __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c index f393986..e0770ac 100644 --- a/sys/nfsserver/nfs_serv.c +++ b/sys/nfsserver/nfs_serv.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_serv.c 8.3 (Berkeley) 1/12/94 - * $Id: nfs_serv.c,v 1.43 1997/06/03 13:56:54 dfr Exp $ + * $Id: nfs_serv.c,v 1.44 1997/06/14 11:19:35 bde Exp $ */ /* @@ -140,7 +140,7 @@ nfsrv3_access(nfsd, slp, procp, mrq) nfsm_srvmtofh(fhp); nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(1, (struct vattr *)0); return (0); @@ -204,7 +204,7 @@ nfsrv_getattr(nfsd, slp, procp, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(0); return (0); } @@ -296,7 +296,7 @@ nfsrv_setattr(nfsd, slp, procp, mrq) * Now that we have all the fields, lets do it. */ if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(2 * NFSX_UNSIGNED); nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); return (0); @@ -365,7 +365,7 @@ nfsrv_lookup(nfsd, slp, procp, mrq) caddr_t dpos = nfsd->nd_dpos; struct ucred *cred = &nfsd->nd_cr; register struct nfs_fattr *fp; - struct nameidata nd; + struct nameidata nd, ind, *ndp = &nd; struct vnode *vp, *dirp; nfsfh_t nfh; fhandle_t *fhp; @@ -374,7 +374,7 @@ nfsrv_lookup(nfsd, slp, procp, mrq) register long t1; caddr_t bpos; int error = 0, cache, len, dirattr_ret = 1; - int v3 = (nfsd->nd_flag & ND_NFSV3); + int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag; char *cp2; struct mbuf *mb, *mb2, *mreq; struct vattr va, dirattr, *vap = &va; @@ -383,26 +383,72 @@ nfsrv_lookup(nfsd, slp, procp, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); nfsm_srvnamesiz(len); + + pubflag = nfs_ispublicfh(fhp); + nd.ni_cnd.cn_cred = cred; nd.ni_cnd.cn_nameiop = LOOKUP; nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), pubflag); + + if (!error && pubflag) { + if (nd.ni_vp->v_type == VDIR && nfs_pub.np_index != NULL) { + /* + * Setup call to lookup() to see if we can find + * the index file. Arguably, this doesn't belong + * in a kernel.. Ugh. + */ + ind = nd; + VOP_UNLOCK(nd.ni_vp, 0, procp); + ind.ni_pathlen = strlen(nfs_pub.np_index); + ind.ni_cnd.cn_nameptr = ind.ni_cnd.cn_pnbuf = + nfs_pub.np_index; + ind.ni_startdir = nd.ni_vp; + VREF(ind.ni_startdir); + error = lookup(&ind); + if (!error) { + /* + * Found an index file. Get rid of + * the old references. + */ + if (dirp) + vrele(dirp); + dirp = nd.ni_vp; + vrele(nd.ni_startdir); + ndp = &ind; + } else + error = 0; + } + /* + * If the public filehandle was used, check that this lookup + * didn't result in a filehandle outside the publicly exported + * filesystem. + */ + + if (!error && ndp->ni_vp->v_mount != nfs_pub.np_mount) { + vput(nd.ni_vp); + error = EPERM; + } + } + if (dirp) { if (v3) dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, procp); vrele(dirp); } + if (error) { nfsm_reply(NFSX_POSTOPATTR(v3)); nfsm_srvpostop_attr(dirattr_ret, &dirattr); return (0); } - nqsrv_getl(nd.ni_startdir, ND_READ); - vrele(nd.ni_startdir); + + nqsrv_getl(ndp->ni_startdir, ND_READ); + vrele(ndp->ni_startdir); FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); - vp = nd.ni_vp; + vp = ndp->ni_vp; bzero((caddr_t)fhp, sizeof(nfh)); fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; error = VFS_VPTOFH(vp, &fhp->fh_fid); @@ -491,7 +537,7 @@ nfsrv_readlink(nfsd, slp, procp, mrq) uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_procp = (struct proc *)0; if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { m_freem(mp3); nfsm_reply(2 * NFSX_UNSIGNED); nfsm_srvpostop_attr(1, (struct vattr *)0); @@ -574,7 +620,7 @@ nfsrv_read(nfsd, slp, procp, mrq) } nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd)); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(2 * NFSX_UNSIGNED); nfsm_srvpostop_attr(1, (struct vattr *)0); return (0); @@ -788,7 +834,7 @@ nfsrv_write(nfsd, slp, procp, mrq) return (0); } if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(2 * NFSX_UNSIGNED); nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); return (0); @@ -1066,7 +1112,7 @@ loop1: v3 = (nfsd->nd_flag & ND_NFSV3); forat_ret = aftat_ret = 1; error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp, - nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH)); + nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE); if (!error) { if (v3) forat_ret = VOP_GETATTR(vp, &forat, cred, procp); @@ -1342,7 +1388,7 @@ nfsrv_create(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -1574,7 +1620,7 @@ nfsrv_mknod(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); if (error) { @@ -1723,7 +1769,7 @@ nfsrv_remove(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = DELETE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -1822,7 +1868,7 @@ nfsrv_rename(nfsd, slp, procp, mrq) fromnd.ni_cnd.cn_nameiop = DELETE; fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md, - &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (fdirp) { if (v3) fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred, @@ -1848,7 +1894,7 @@ nfsrv_rename(nfsd, slp, procp, mrq) tond.ni_cnd.cn_nameiop = RENAME; tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; error = nfs_namei(&tond, tfhp, len2, slp, nam, &md, - &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (tdirp) { if (v3) tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred, @@ -2014,7 +2060,7 @@ nfsrv_link(nfsd, slp, procp, mrq) nfsm_srvmtofh(dfhp); nfsm_srvnamesiz(len); if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); nfsm_srvpostop_attr(getret, &at); nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); @@ -2028,7 +2074,7 @@ nfsrv_link(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT; error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2122,7 +2168,7 @@ nfsrv_symlink(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2264,7 +2310,7 @@ nfsrv_mkdir(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = CREATE; nd.ni_cnd.cn_flags = LOCKPARENT; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2377,7 +2423,7 @@ nfsrv_rmdir(nfsd, slp, procp, mrq) nd.ni_cnd.cn_nameiop = DELETE; nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, - &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH)); + &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE); if (dirp) { if (v3) dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, @@ -2526,7 +2572,7 @@ nfsrv_readdir(nfsd, slp, procp, mrq) siz = xfer; fullsiz = siz; if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); return (0); @@ -2790,7 +2836,7 @@ nfsrv_readdirplus(nfsd, slp, procp, mrq) siz = xfer; fullsiz = siz; if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); return (0); @@ -3095,7 +3141,7 @@ nfsrv_commit(nfsd, slp, procp, mrq) tl += 2; cnt = fxdr_unsigned(int, *tl); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(2 * NFSX_UNSIGNED); nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); return (0); @@ -3151,7 +3197,7 @@ nfsrv_statfs(nfsd, slp, procp, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); return (0); @@ -3226,7 +3272,7 @@ nfsrv_fsinfo(nfsd, slp, procp, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); return (0); @@ -3297,7 +3343,7 @@ nfsrv_pathconf(nfsd, slp, procp, mrq) fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, - &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) { + &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE)) { nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); return (0); diff --git a/sys/nfsserver/nfs_srvsubs.c b/sys/nfsserver/nfs_srvsubs.c index 572ccc2..105bc52 100644 --- a/sys/nfsserver/nfs_srvsubs.c +++ b/sys/nfsserver/nfs_srvsubs.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94 - * $Id: nfs_subs.c,v 1.37 1997/02/22 09:42:41 peter Exp $ + * $Id: nfs_subs.c,v 1.38 1997/04/04 17:49:29 dfr Exp $ */ /* @@ -53,6 +53,7 @@ #include <sys/socket.h> #include <sys/stat.h> #include <sys/malloc.h> +#include <sys/dirent.h> #ifdef VFS_LKM #include <sys/sysent.h> #include <sys/syscall.h> @@ -560,6 +561,8 @@ extern int nfssvc(struct proc *, struct nfssvc_args *, int *); LIST_HEAD(nfsnodehashhead, nfsnode); +int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); + /* * Create the header for an rpc request packet * The hsiz is the size of the rest of the nfs request header. @@ -1412,10 +1415,16 @@ nfs_getattrcache(vp, vaper) #ifndef NFS_NOSERVER /* - * Set up nameidata for a lookup() call and do it + * Set up nameidata for a lookup() call and do it. + * + * If pubflag is set, this call is done for a lookup operation on the + * public filehandle. In that case we allow crossing mountpoints and + * absolute pathnames. However, the caller is expected to check that + * the lookup result is within the public fs, and deny access if + * it is not. */ int -nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) +nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) register struct nameidata *ndp; fhandle_t *fhp; int len; @@ -1425,13 +1434,15 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) caddr_t *dposp; struct vnode **retdirp; struct proc *p; - int kerbflag; + int kerbflag, pubflag; { register int i, rem; register struct mbuf *md; - register char *fromcp, *tocp; + register char *fromcp, *tocp, *cp; + struct iovec aiov; + struct uio auio; struct vnode *dp; - int error, rdonly; + int error, rdonly, linklen; struct componentname *cnp = &ndp->ni_cnd; *retdirp = (struct vnode *)0; @@ -1455,7 +1466,7 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) fromcp = mtod(md, caddr_t); rem = md->m_len; } - if (*fromcp == '\0' || *fromcp == '/') { + if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { error = EACCES; goto out; } @@ -1473,55 +1484,170 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) else if (error = nfs_adv(mdp, dposp, len, rem)) goto out; } - ndp->ni_pathlen = tocp - cnp->cn_pnbuf; - cnp->cn_nameptr = cnp->cn_pnbuf; + /* * Extract and set starting directory. */ - if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, - nam, &rdonly, kerbflag)) + error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, + nam, &rdonly, kerbflag, pubflag); + if (error) goto out; if (dp->v_type != VDIR) { vrele(dp); error = ENOTDIR; goto out; } + + if (rdonly) + cnp->cn_flags |= RDONLY; + + if (pubflag) { + /* + * Oh joy. For WebNFS, handle those pesky '%' escapes, + * and the 'native path' indicator. + */ + MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + fromcp = cnp->cn_pnbuf; + tocp = cp; + if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { + switch ((unsigned char)*fromcp) { + case WEBNFS_NATIVE_CHAR: + /* + * 'Native' path for us is the same + * as a path according to the NFS spec, + * just skip the escape char. + */ + fromcp++; + break; + /* + * More may be added in the future, range 0x80-0xff + */ + default: + error = EIO; + FREE(cp, M_NAMEI); + goto out; + } + } + /* + * Translate the '%' escapes, URL-style. + */ + while (*fromcp != '\0') { + if (*fromcp == WEBNFS_ESC_CHAR) { + if (fromcp[1] != '\0' && fromcp[2] != '\0') { + fromcp++; + *tocp++ = HEXSTRTOI(fromcp); + fromcp += 2; + continue; + } else { + error = ENOENT; + FREE(cp, M_NAMEI); + goto out; + } + } else + *tocp++ = *fromcp++; + } + *tocp = '\0'; + FREE(cnp->cn_pnbuf, M_NAMEI); + cnp->cn_pnbuf = cp; + } + + ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; + ndp->ni_segflg = UIO_SYSSPACE; + + if (pubflag) { + ndp->ni_rootdir = rootvnode; + ndp->ni_loopcnt = 0; + if (cnp->cn_pnbuf[0] == '/') + dp = rootvnode; + } else { + cnp->cn_flags |= NOCROSSMOUNT; + } + + cnp->cn_proc = p; VREF(dp); - *retdirp = dp; + + for (;;) { + cnp->cn_nameptr = cnp->cn_pnbuf; ndp->ni_startdir = dp; - if (rdonly) - cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); - else - cnp->cn_flags |= NOCROSSMOUNT; /* * And call lookup() to do the real work */ cnp->cn_proc = p; if (error = lookup(ndp)) - goto out; + break; /* * Check for encountering a symbolic link */ - if (cnp->cn_flags & ISSYMLINK) { + if ((cnp->cn_flags & ISSYMLINK) == 0) { + nfsrv_object_create(ndp->ni_vp); + if (cnp->cn_flags & (SAVENAME | SAVESTART)) { + cnp->cn_flags |= HASBUF; + return (0); + } + break; + } else { if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) - vput(ndp->ni_dvp); - else + VOP_UNLOCK(ndp->ni_dvp, 0, p); + if (!pubflag) { vrele(ndp->ni_dvp); - vput(ndp->ni_vp); - ndp->ni_vp = NULL; - error = EINVAL; - goto out; - } - - nfsrv_object_create(ndp->ni_vp); + vput(ndp->ni_vp); + ndp->ni_vp = NULL; + error = EINVAL; + break; + } - /* - * Check for saved name request - */ - if (cnp->cn_flags & (SAVENAME | SAVESTART)) { - cnp->cn_flags |= HASBUF; - return (0); + if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { + error = ELOOP; + break; + } + if (ndp->ni_pathlen > 0) + MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + else + cp = cnp->cn_pnbuf; + aiov.iov_base = cp; + aiov.iov_len = MAXPATHLEN; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = (struct proc *)0; + auio.uio_resid = MAXPATHLEN; + error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); + if (error) { + badlink: + if (ndp->ni_pathlen > 1) + FREE(cp, M_NAMEI); + break; + } + linklen = MAXPATHLEN - auio.uio_resid; + if (linklen == 0) { + error = ENOENT; + goto badlink; + } + if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { + error = ENAMETOOLONG; + goto badlink; + } + if (ndp->ni_pathlen > 1) { + bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); + FREE(cnp->cn_pnbuf, M_NAMEI); + cnp->cn_pnbuf = cp; + } else + cnp->cn_pnbuf[linklen] = '\0'; + ndp->ni_pathlen += linklen; + vput(ndp->ni_vp); + dp = ndp->ni_dvp; + /* + * Check if root directory should replace current directory. + */ + if (cnp->cn_pnbuf[0] == '/') { + vrele(dp); + dp = ndp->ni_rootdir; + VREF(dp); + } } + } out: FREE(cnp->cn_pnbuf, M_NAMEI); return (error); @@ -1700,7 +1826,7 @@ nfsm_srvfattr(nfsd, vap, fp) * - if not lockflag unlock it with VOP_UNLOCK() */ int -nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) +nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) fhandle_t *fhp; int lockflag; struct vnode **vpp; @@ -1709,6 +1835,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) struct mbuf *nam; int *rdonlyp; int kerbflag; + int pubflag; { struct proc *p = curproc; /* XXX */ register struct mount *mp; @@ -1717,6 +1844,13 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) int error, exflags; *vpp = (struct vnode *)0; + + if (nfs_ispublicfh(fhp)) { + if (!pubflag || !nfs_pub.np_valid) + return (ESTALE); + fhp = &nfs_pub.np_handle; + } + mp = vfs_getvfs(&fhp->fh_fsid); if (!mp) return (ESTALE); @@ -1752,6 +1886,25 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) return (0); } + +/* + * WebNFS: check if a filehandle is a public filehandle. For v3, this + * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has + * transformed this to all zeroes in both cases, so check for it. + */ +int +nfs_ispublicfh(fhp) + fhandle_t *fhp; +{ + char *cp = (char *)fhp; + int i; + + for (i = 0; i < NFSX_V3FH; i++) + if (*cp++ != 0) + return (FALSE); + return (TRUE); +} + #endif /* NFS_NOSERVER */ /* * This function compares two net addresses by family and returns TRUE diff --git a/sys/nfsserver/nfs_syscalls.c b/sys/nfsserver/nfs_syscalls.c index de07c23..0c46e28 100644 --- a/sys/nfsserver/nfs_syscalls.c +++ b/sys/nfsserver/nfs_syscalls.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs_syscalls.c 8.5 (Berkeley) 3/30/95 - * $Id: nfs_syscalls.c,v 1.24 1997/05/13 17:25:44 dfr Exp $ + * $Id: nfs_syscalls.c,v 1.25 1997/06/25 21:07:26 tegge Exp $ */ #include <sys/param.h> @@ -1129,7 +1129,8 @@ nfsrv_init(terminating) free((caddr_t)slp, M_NFSSVC); } nfsrv_cleancache(); /* And clear out server cache */ - } + } else + nfs_pub.np_valid = 0; TAILQ_INIT(&nfssvc_sockhead); nfssvc_sockhead_flag &= ~SLP_INIT; diff --git a/sys/nfsserver/nfsm_subs.h b/sys/nfsserver/nfsm_subs.h index c2677c8..e33be82 100644 --- a/sys/nfsserver/nfsm_subs.h +++ b/sys/nfsserver/nfsm_subs.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfsm_subs.h 8.2 (Berkeley) 3/30/95 - * $Id$ + * $Id: nfsm_subs.h,v 1.12 1997/02/22 09:42:48 peter Exp $ */ @@ -363,18 +363,24 @@ struct mbuf *nfsm_rpchead __P((struct ucred *cr, int nmflag, int procid, } } #define nfsm_srvmtofh(f) \ - { if (nfsd->nd_flag & ND_NFSV3) { \ + { int fhlen = NFSX_V3FH; \ + if (nfsd->nd_flag & ND_NFSV3) { \ nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); \ - if (fxdr_unsigned(int, *tl) != NFSX_V3FH) { \ + fhlen = fxdr_unsigned(int, *tl); \ + if (fhlen == 0) { \ + bzero((caddr_t)(f), NFSX_V3FH); \ + } else if (fhlen != NFSX_V3FH) { \ error = EBADRPC; \ nfsm_reply(0); \ } \ } \ - nfsm_dissect(tl, u_long *, NFSX_V3FH); \ - bcopy((caddr_t)tl, (caddr_t)(f), NFSX_V3FH); \ - if ((nfsd->nd_flag & ND_NFSV3) == 0) \ - nfsm_adv(NFSX_V2FH - NFSX_V3FH); \ - } + if (fhlen != 0) { \ + nfsm_dissect(tl, u_long *, NFSX_V3FH); \ + bcopy((caddr_t)tl, (caddr_t)(f), NFSX_V3FH); \ + if ((nfsd->nd_flag & ND_NFSV3) == 0) \ + nfsm_adv(NFSX_V2FH - NFSX_V3FH); \ + } \ + } #define nfsm_clget \ if (bp >= be) { \ diff --git a/sys/nfsserver/nfsrvstats.h b/sys/nfsserver/nfsrvstats.h index 3521dae..528a366 100644 --- a/sys/nfsserver/nfsrvstats.h +++ b/sys/nfsserver/nfsrvstats.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)nfs.h 8.4 (Berkeley) 5/1/95 - * $Id: nfs.h,v 1.27 1997/05/19 14:36:46 dfr Exp $ + * $Id: nfs.h,v 1.28 1997/06/03 17:22:45 dfr Exp $ */ #ifndef _NFS_NFS_H_ @@ -522,6 +522,30 @@ extern int nfsd_head_flag; !bcmp((caddr_t)&(o)->nd_cr, (caddr_t)&(n)->nd_cr, \ sizeof (struct ucred))) +/* + * Defines for WebNFS + */ + +#define WEBNFS_ESC_CHAR '%' +#define WEBNFS_SPECCHAR_START 0x80 + +#define WEBNFS_NATIVE_CHAR 0x80 +/* + * .. + * Possibly more here in the future. + */ + +/* + * Macro for converting escape characters in WebNFS pathnames. + * Should really be in libkern. + */ + +#define HEXTOC(c) \ + ((c) >= 'a' ? ((c) - ('a' - 10)) : \ + ((c) >= 'A' ? ((c) - ('A' - 10)) : ((c) - '0'))) +#define HEXSTRTOI(p) \ + ((HEXTOC(p[0]) << 4) + HEXTOC(p[1])) + #ifdef NFS_DEBUG extern int nfs_debug; @@ -564,7 +588,7 @@ void nfsm_srvpostopattr __P((struct nfsrv_descript *,int,struct vattr *,struct m int netaddr_match __P((int,union nethostaddr *,struct mbuf *)); int nfs_request __P((struct vnode *,struct mbuf *,int,struct proc *,struct ucred *,struct mbuf **,struct mbuf **,caddr_t *)); int nfs_loadattrcache __P((struct vnode **,struct mbuf **,caddr_t *,struct vattr *)); -int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int)); +int nfs_namei __P((struct nameidata *,fhandle_t *,int,struct nfssvc_sock *,struct mbuf *,struct mbuf **,caddr_t *,struct vnode **,struct proc *,int,int)); void nfsm_adj __P((struct mbuf *,int,int)); int nfsm_mbuftouio __P((struct mbuf **,struct uio *,int,caddr_t *)); void nfsrv_initcache __P((void)); @@ -606,7 +630,10 @@ int nfsrv_create __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_fhtovp __P((fhandle_t *,int,struct vnode **, struct ucred *,struct nfssvc_sock *,struct mbuf *, - int *,int)); + int *,int,int)); +int nfsrv_setpublicfs __P((struct mount *, struct netexport *, + struct export_args *)); +int nfs_ispublicfh __P((fhandle_t *)); int nfsrv_fsinfo __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct proc *procp, struct mbuf **mrq)); int nfsrv_getattr __P((struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, |