Extend lookup handling for WebNFS. This means that nfs_namei deals
with full pathname lookups if a public filehandle is used, and that it translates the '%' escapes (URL-style) in the same case. Also, make nfsrv_fhtovp convert the public filehandle to the vp of the publicly exported filesystem, as stored in the nfs_pub structure.
This commit is contained in:
parent
6611bf92a5
commit
28e824c9b7
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: nfs_subs.c,v 1.42 1997/05/08 16:20:35 mycroft Exp $ */
|
||||
/* $NetBSD: nfs_subs.c,v 1.43 1997/06/24 23:36:02 fvdl Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
|
@ -56,6 +56,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/dirent.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
|
||||
|
@ -98,6 +99,7 @@ nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
|
|||
enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
|
||||
enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
|
||||
int nfs_ticks;
|
||||
extern struct nfs_public nfs_pub;
|
||||
|
||||
/* NFS client/server stats. */
|
||||
struct nfsstats nfsstats;
|
||||
|
@ -536,6 +538,8 @@ extern u_long nfsnodehash;
|
|||
|
||||
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.
|
||||
|
@ -1418,10 +1422,16 @@ nfs_getattrcache(vp, vaper)
|
|||
#endif /* NFS */
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
@ -1431,13 +1441,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;
|
||||
|
@ -1460,7 +1472,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;
|
||||
}
|
||||
|
@ -1477,13 +1489,12 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
|
|||
else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
|
||||
goto out;
|
||||
}
|
||||
ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
|
||||
cnp->cn_nameptr = cnp->cn_pnbuf;
|
||||
|
||||
/*
|
||||
* Extract and set starting directory.
|
||||
*/
|
||||
error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
|
||||
nam, &rdonly, kerbflag);
|
||||
nam, &rdonly, kerbflag, pubflag);
|
||||
if (error)
|
||||
goto out;
|
||||
if (dp->v_type != VDIR) {
|
||||
|
@ -1491,40 +1502,158 @@ nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
|
|||
error = ENOTDIR;
|
||||
goto out;
|
||||
}
|
||||
VREF(dp);
|
||||
*retdirp = dp;
|
||||
ndp->ni_startdir = dp;
|
||||
|
||||
if (rdonly)
|
||||
cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
|
||||
else
|
||||
cnp->cn_flags |= RDONLY;
|
||||
|
||||
*retdirp = dp;
|
||||
|
||||
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);
|
||||
|
||||
for (;;) {
|
||||
cnp->cn_nameptr = cnp->cn_pnbuf;
|
||||
ndp->ni_startdir = dp;
|
||||
/*
|
||||
* And call lookup() to do the real work
|
||||
*/
|
||||
cnp->cn_proc = p;
|
||||
error = lookup(ndp);
|
||||
if (error)
|
||||
goto out;
|
||||
break;
|
||||
/*
|
||||
* Check for encountering a symbolic link
|
||||
*/
|
||||
if (cnp->cn_flags & ISSYMLINK) {
|
||||
if ((cnp->cn_flags & ISSYMLINK) == 0) {
|
||||
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);
|
||||
if (!pubflag) {
|
||||
vrele(ndp->ni_dvp);
|
||||
vput(ndp->ni_vp);
|
||||
ndp->ni_vp = NULL;
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
|
||||
error = ELOOP;
|
||||
break;
|
||||
}
|
||||
if (ndp->ni_pathlen > 1)
|
||||
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);
|
||||
ndp->ni_vp = NULL;
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* Check for saved name request
|
||||
*/
|
||||
if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
|
||||
cnp->cn_flags |= HASBUF;
|
||||
return (0);
|
||||
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);
|
||||
|
@ -1703,7 +1832,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;
|
||||
|
@ -1723,6 +1852,13 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
|
|||
struct sockaddr_in *saddr;
|
||||
|
||||
*vpp = (struct vnode *)0;
|
||||
|
||||
if (nfs_ispublicfh(fhp)) {
|
||||
if (!pubflag || !nfs_pub.np_valid)
|
||||
return (ESTALE);
|
||||
fhp = &nfs_pub.np_handle;
|
||||
}
|
||||
|
||||
#ifdef Lite2_integrated
|
||||
mp = vfs_getvfs(&fhp->fh_fsid);
|
||||
#else
|
||||
|
@ -1734,7 +1870,7 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
|
|||
if (error)
|
||||
return (error);
|
||||
|
||||
if (!(exflags & MNT_EXNORESPORT)) {
|
||||
if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
|
||||
saddr = mtod(nam, struct sockaddr_in *);
|
||||
if (saddr->sin_family == AF_INET &&
|
||||
ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
|
||||
|
@ -1773,6 +1909,24 @@ 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function compares two net addresses by family and returns TRUE
|
||||
* if they are the same host.
|
||||
|
|
Loading…
Reference in New Issue