Index: nfsserver/nfs_serv.c =================================================================== --- nfsserver/nfs_serv.c (revision 2) +++ nfsserver/nfs_serv.c (working copy) @@ -128,11 +128,39 @@ SYSCTL_NODE(_vfs, OID_AUTO, nfsrv, CTLFLAG_RW, 0, "NFS server"); static int nfs_suiddir_override_minuid = 0; static int nfs_suiddir_override_maxuid = 0; +static uint32_t nfs_suiddir_force_mode_file = 0; +static uint32_t nfs_suiddir_force_mode_dir = 0; +static uint32_t nfs_suiddir_force_umask = 0; +static int nfs_suiddir_force_minuid = 1; +static int nfs_suiddir_force_maxuid = 0; SYSCTL_UINT(_vfs_nfsrv, OID_AUTO, nfs_suiddir_override_minuid, CTLFLAG_RW, &nfs_suiddir_override_minuid, 0, ""); SYSCTL_UINT(_vfs_nfsrv, OID_AUTO, nfs_suiddir_override_maxuid, CTLFLAG_RW, &nfs_suiddir_override_maxuid, 0, ""); +SYSCTL_UINT(_vfs_nfsrv, OID_AUTO, nfs_suiddir_force_mode_file, CTLFLAG_RW, + &nfs_suiddir_force_mode_file, 0, ""); +SYSCTL_UINT(_vfs_nfsrv, OID_AUTO, nfs_suiddir_force_mode_dir, CTLFLAG_RW, + &nfs_suiddir_force_mode_dir, 0, ""); +SYSCTL_UINT(_vfs_nfsrv, OID_AUTO, nfs_suiddir_force_umask, CTLFLAG_RW, + &nfs_suiddir_force_umask, 0, ""); +SYSCTL_UINT(_vfs_nfsrv, OID_AUTO, nfs_suiddir_force_minuid, CTLFLAG_RW, + &nfs_suiddir_force_minuid, 0, ""); +SYSCTL_UINT(_vfs_nfsrv, OID_AUTO, nfs_suiddir_force_maxuid, CTLFLAG_RW, + &nfs_suiddir_force_maxuid, 0, ""); +#define HANDLE_SUID_FORCE_FLAGS(flg,tpe) \ + if (flg & MNT_SUIDDIR && cred->cr_uid >= nfs_suiddir_force_minuid && \ + cred->cr_uid <= nfs_suiddir_force_maxuid && \ + (tpe == VREG || tpe == VDIR)) { \ + if (vap->va_mode == (mode_t)VNOVAL) \ + vap->va_mode = 0; \ + vap->va_mode &= ~nfs_suiddir_force_umask; \ + if (tpe == VREG) \ + vap->va_mode |= nfs_suiddir_force_mode_file; \ + else if (tpe == VDIR) \ + vap->va_mode |= nfs_suiddir_force_mode_dir; \ + } \ + static int nfs_async; static int nfs_commit_blks; static int nfs_commit_miss; @@ -443,6 +471,7 @@ td, 0)) != 0) goto out; } + HANDLE_SUID_FORCE_FLAGS(vp->v_mount->mnt_flag,vp->v_type); error = VOP_SETATTR(vp, vap, cred, td); postat_ret = VOP_GETATTR(vp, vap, cred, td); if (!error) @@ -1670,6 +1699,7 @@ struct mount *mp = NULL; int tvfslocked; int vfslocked; + int mnt_flag; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); vfslocked = 0; @@ -1684,6 +1714,7 @@ error = ESTALE; goto ereply; } + mnt_flag = mp->mnt_flag; /* XXX race (unlikely though) */ vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ @@ -1772,6 +1803,7 @@ break; }; } + HANDLE_SUID_FORCE_FLAGS(mnt_flag, vap->va_type); /* * Iff doesn't exist, create it @@ -1794,6 +1826,7 @@ VATTR_NULL(vap); bcopy(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF); + HANDLE_SUID_FORCE_FLAGS(mnt_flag, vap->va_type); error = VOP_SETATTR(nd.ni_vp, vap, cred, td); } @@ -1963,6 +1996,7 @@ int v3 = (nfsd->nd_flag & ND_NFSV3); int tvfslocked; int vfslocked; + int mnt_flag; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); vfslocked = 0; @@ -1976,6 +2010,7 @@ error = ESTALE; goto ereply; } + mnt_flag = mp->mnt_flag; /* XXX race (unlikely though) */ vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ @@ -2025,6 +2060,7 @@ vap->va_type = vtyp; if (vap->va_mode == (mode_t)VNOVAL) vap->va_mode = 0; + HANDLE_SUID_FORCE_FLAGS(mnt_flag, vtyp); if (vtyp == VSOCK) { vrele(nd.ni_startdir); nd.ni_startdir = NULL; @@ -2653,6 +2689,7 @@ struct mount *mp = NULL; int tvfslocked; int vfslocked; + int mnt_flag; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); ndclear(&nd); @@ -2664,6 +2701,7 @@ error = ESTALE; goto out; } + mnt_flag = mp->mnt_flag; /* XXX race (unlikely though) */ vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ @@ -2713,6 +2751,7 @@ */ if (vap->va_mode == (mode_t)VNOVAL) vap->va_mode = 0; + HANDLE_SUID_FORCE_FLAGS(mnt_flag, vap->va_type); error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); if (error) NDFREE(&nd, NDF_ONLY_PNBUF); @@ -2836,6 +2875,7 @@ fhandle_t *fhp; struct mount *mp = NULL; int vfslocked; + int mnt_flag; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); ndclear(&nd); @@ -2848,6 +2888,7 @@ goto out; } vfslocked = VFS_LOCK_GIANT(mp); + mnt_flag = mp->mnt_flag; /* XXX race (unlikely though) */ (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ nfsm_srvnamesiz(len); @@ -2896,6 +2937,7 @@ */ if (vap->va_mode == (mode_t)VNOVAL) vap->va_mode = 0; + HANDLE_SUID_FORCE_FLAGS(mnt_flag, vap->va_type); error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap); NDFREE(&nd, NDF_ONLY_PNBUF); vpexcl = 1;