Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c =================================================================== --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c @@ -101,8 +101,8 @@ static int zfs_statfs(vfs_t *vfsp, struct statfs *statp); static int zfs_vget(vfs_t *vfsp, ino_t ino, int flags, vnode_t **vpp); static int zfs_sync(vfs_t *vfsp, int waitfor); -static int zfs_checkexp(vfs_t *vfsp, struct sockaddr *nam, int *extflagsp, - struct ucred **credanonp, int *numsecflavors, int **secflavors); +static int zfs_checkexp(vfs_t *vfsp, struct sockaddr *nam, uint64_t *extflagsp, + struct ucred **credanonp, int *numsecflavors, int *secflavors); static int zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, int flags, vnode_t **vpp); static void zfs_objset_close(zfsvfs_t *zfsvfs); static void zfs_freevfs(vfs_t *vfsp); @@ -2268,8 +2268,8 @@ } static int -zfs_checkexp(vfs_t *vfsp, struct sockaddr *nam, int *extflagsp, - struct ucred **credanonp, int *numsecflavors, int **secflavors) +zfs_checkexp(vfs_t *vfsp, struct sockaddr *nam, uint64_t *extflagsp, + struct ucred **credanonp, int *numsecflavors, int *secflavors) { zfsvfs_t *zfsvfs = vfsp->vfs_data; Index: sys/fs/cd9660/cd9660_vfsops.c =================================================================== --- sys/fs/cd9660/cd9660_vfsops.c +++ sys/fs/cd9660/cd9660_vfsops.c @@ -101,16 +101,14 @@ cd9660_cmount(struct mntarg *ma, void *data, uint64_t flags) { struct iso_args args; - struct export_args exp; int error; error = copyin(data, &args, sizeof args); if (error) return (error); - vfs_oexport_conv(&args.export, &exp); ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); - ma = mount_arg(ma, "export", &exp, sizeof(exp)); + ma = mount_arg(ma, "export", &args.export, sizeof(args.export)); ma = mount_argsu(ma, "cs_disk", args.cs_disk, 64); ma = mount_argsu(ma, "cs_local", args.cs_local, 64); ma = mount_argf(ma, "ssector", "%u", args.ssector); Index: sys/fs/msdosfs/msdosfs_vfsops.c =================================================================== --- sys/fs/msdosfs/msdosfs_vfsops.c +++ sys/fs/msdosfs/msdosfs_vfsops.c @@ -190,7 +190,6 @@ msdosfs_cmount(struct mntarg *ma, void *data, uint64_t flags) { struct msdosfs_args args; - struct export_args exp; int error; if (data == NULL) @@ -198,10 +197,9 @@ error = copyin(data, &args, sizeof args); if (error) return (error); - vfs_oexport_conv(&args.export, &exp); ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); - ma = mount_arg(ma, "export", &exp, sizeof(exp)); + ma = mount_arg(ma, "export", &args.export, sizeof(args.export)); ma = mount_argf(ma, "uid", "%d", args.uid); ma = mount_argf(ma, "gid", "%d", args.gid); ma = mount_argf(ma, "mask", "%d", args.mask); Index: sys/fs/nfs/nfsdport.h =================================================================== --- sys/fs/nfs/nfsdport.h +++ sys/fs/nfs/nfsdport.h @@ -54,7 +54,7 @@ * needs to be returned by nfsd_fhtovp(). */ struct nfsexstuff { - int nes_exflag; /* export flags */ + uint64_t nes_exflag; /* export flags */ int nes_numsecflavor; /* # of security flavors */ int nes_secflavors[MAXSECFLAVORS]; /* and the flavors */ }; Index: sys/fs/nfs/nfsport.h =================================================================== --- sys/fs/nfs/nfsport.h +++ sys/fs/nfs/nfsport.h @@ -1081,6 +1081,11 @@ struct export_args export; }; +struct nfsex_oldargs { + char *fspec; + struct o2export_args export; +}; + /* * These export flags should be defined, but there are no bits left. * Maybe a separate mnt_exflag field could be added or the mnt_flag Index: sys/fs/nfsserver/nfs_nfsdport.c =================================================================== --- sys/fs/nfsserver/nfs_nfsdport.c +++ sys/fs/nfsserver/nfs_nfsdport.c @@ -3056,10 +3056,10 @@ nfsvno_checkexp(struct mount *mp, struct sockaddr *nam, struct nfsexstuff *exp, struct ucred **credp) { - int i, error, *secflavors; + int error; error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp, - &exp->nes_numsecflavor, &secflavors); + &exp->nes_numsecflavor, exp->nes_secflavors); if (error) { if (nfs_rootfhset) { exp->nes_exflag = 0; @@ -3071,10 +3071,6 @@ printf("nfsvno_checkexp: numsecflavors out of range\n"); exp->nes_numsecflavor = 0; error = EACCES; - } else { - /* Copy the security flavors. */ - for (i = 0; i < exp->nes_numsecflavor; i++) - exp->nes_secflavors[i] = secflavors[i]; } NFSEXITCODE(error); return (error); @@ -3088,7 +3084,7 @@ int lktype, struct vnode **vpp, struct nfsexstuff *exp, struct ucred **credp) { - int i, error, *secflavors; + int error; *credp = NULL; exp->nes_numsecflavor = 0; @@ -3098,7 +3094,7 @@ error = ESTALE; if (nam && !error) { error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp, - &exp->nes_numsecflavor, &secflavors); + &exp->nes_numsecflavor, exp->nes_secflavors); if (error) { if (nfs_rootfhset) { exp->nes_exflag = 0; @@ -3113,10 +3109,6 @@ exp->nes_numsecflavor = 0; error = EACCES; vput(*vpp); - } else { - /* Copy the security flavors. */ - for (i = 0; i < exp->nes_numsecflavor; i++) - exp->nes_secflavors[i] = secflavors[i]; } } NFSEXITCODE(error); @@ -3415,10 +3407,11 @@ nfsvno_v4rootexport(struct nfsrv_descript *nd) { struct ucred *credanon; - int exflags, error = 0, numsecflavor, *secflavors, i; + int error = 0, numsecflavor, secflavors[MAXSECFLAVORS], i; + uint64_t exflags; error = vfs_stdcheckexp(&nfsv4root_mnt, nd->nd_nam, &exflags, - &credanon, &numsecflavor, &secflavors); + &credanon, &numsecflavor, secflavors); if (error) { error = NFSERR_PROGUNAVAIL; goto out; @@ -3656,8 +3649,9 @@ nfssvc_srvcall(struct thread *p, struct nfssvc_args *uap, struct ucred *cred) { struct nfsex_args export; + struct nfsex_oldargs oexp; struct file *fp = NULL; - int stablefd, len; + int stablefd, i, len; struct nfsd_clid adminrevoke; struct nfsd_dumplist dumplist; struct nfsd_dumpclients *dumpclients; @@ -3667,6 +3661,7 @@ vnode_t vp; int error = EINVAL, igotlock; struct proc *procp; + gid_t *grps; static int suspend_nfsd = 0; if (uap->flag & NFSSVC_PUBLICFH) { @@ -3676,11 +3671,71 @@ &nfs_pubfh.nfsrvfh_data, sizeof (fhandle_t)); if (!error) nfs_pubfhset = 1; - } else if (uap->flag & NFSSVC_V4ROOTEXPORT) { + } else if ((uap->flag & (NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT)) == + (NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT)) { error = copyin(uap->argp,(caddr_t)&export, sizeof (struct nfsex_args)); - if (!error) - error = nfsrv_v4rootexport(&export, cred, p); + if (!error) { + grps = NULL; + if (export.export.ex_ngroups > NGROUPS_MAX || + export.export.ex_ngroups < 0) + error = EINVAL; + else if (export.export.ex_ngroups > 0) { + grps = malloc(export.export.ex_ngroups * + sizeof(gid_t), M_TEMP, M_WAITOK); + error = copyin(export.export.ex_groups, grps, + export.export.ex_ngroups * sizeof(gid_t)); + export.export.ex_groups = grps; + } else + export.export.ex_groups = NULL; + if (!error) + error = nfsrv_v4rootexport(&export, cred, p); + free(grps, M_TEMP); + } + } else if ((uap->flag & (NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT)) == + NFSSVC_V4ROOTEXPORT) { + error = copyin(uap->argp,(caddr_t)&oexp, + sizeof (struct nfsex_oldargs)); + if (!error) { + memset(&export.export, 0, sizeof(export.export)); + export.export.ex_flags = (uint64_t)oexp.export.ex_flags; + export.export.ex_root = oexp.export.ex_root; + export.export.ex_uid = oexp.export.ex_anon.cr_uid; + export.export.ex_ngroups = + oexp.export.ex_anon.cr_ngroups; + export.export.ex_groups = NULL; + if (export.export.ex_ngroups > XU_NGROUPS || + export.export.ex_ngroups < 0) + error = EINVAL; + else if (export.export.ex_ngroups > 0) { + export.export.ex_groups = malloc( + export.export.ex_ngroups * sizeof(gid_t), + M_TEMP, M_WAITOK); + for (i = 0; i < export.export.ex_ngroups; i++) + export.export.ex_groups[i] = + oexp.export.ex_anon.cr_groups[i]; + } + export.export.ex_addr = oexp.export.ex_addr; + export.export.ex_addrlen = oexp.export.ex_addrlen; + export.export.ex_mask = oexp.export.ex_mask; + export.export.ex_masklen = oexp.export.ex_masklen; + export.export.ex_indexfile = oexp.export.ex_indexfile; + export.export.ex_numsecflavors = + oexp.export.ex_numsecflavors; + if (export.export.ex_numsecflavors >= MAXSECFLAVORS || + export.export.ex_numsecflavors < 0) + error = EINVAL; + else { + for (i = 0; i < export.export.ex_numsecflavors; + i++) + export.export.ex_secflavors[i] = + oexp.export.ex_secflavors[i]; + } + export.fspec = oexp.fspec; + if (error == 0) + error = nfsrv_v4rootexport(&export, cred, p); + free(export.export.ex_groups, M_TEMP); + } } else if (uap->flag & NFSSVC_NOPUBLICFH) { nfs_pubfhset = 0; error = 0; Index: sys/fs/unionfs/union_vfsops.c =================================================================== --- sys/fs/unionfs/union_vfsops.c +++ sys/fs/unionfs/union_vfsops.c @@ -466,8 +466,8 @@ } static int -unionfs_checkexp(struct mount *mp, struct sockaddr *nam, int *extflagsp, - struct ucred **credanonp, int *numsecflavors, int **secflavors) +unionfs_checkexp(struct mount *mp, struct sockaddr *nam, uint64_t *extflagsp, + struct ucred **credanonp, int *numsecflavors, int *secflavors) { return (EOPNOTSUPP); } Index: sys/kern/vfs_export.c =================================================================== --- sys/kern/vfs_export.c +++ sys/kern/vfs_export.c @@ -79,7 +79,7 @@ */ struct netcred { struct radix_node netc_rnodes[2]; - int netc_exflags; + uint64_t netc_exflags; struct ucred *netc_anon; int netc_numsecflavors; int netc_secflavors[MAXSECFLAVORS]; @@ -118,18 +118,12 @@ ("%s: numsecflavors >= MAXSECFLAVORS", __func__)); /* - * XXX: This routine converts from a `struct xucred' - * (argp->ex_anon) to a `struct ucred' (np->netc_anon). This + * XXX: This routine converts from a uid plus gid list + * to a `struct ucred' (np->netc_anon). This * operation is questionable; for example, what should be done * with fields like cr_uidinfo and cr_prison? Currently, this * routine does not touch them (leaves them as NULL). */ - if (argp->ex_anon.cr_version != XUCRED_VERSION) { - vfs_mount_error(mp, "ex_anon.cr_version: %d != %d", - argp->ex_anon.cr_version, XUCRED_VERSION); - return (EINVAL); - } - if (argp->ex_addrlen == 0) { if (mp->mnt_flag & MNT_DEFEXPORTED) { vfs_mount_error(mp, @@ -139,9 +133,9 @@ np = &nep->ne_defexported; np->netc_exflags = argp->ex_flags; np->netc_anon = crget(); - np->netc_anon->cr_uid = argp->ex_anon.cr_uid; - crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups, - argp->ex_anon.cr_groups); + np->netc_anon->cr_uid = argp->ex_uid; + crsetgroups(np->netc_anon, argp->ex_ngroups, + argp->ex_groups); np->netc_anon->cr_prison = &prison0; prison_hold(np->netc_anon->cr_prison); np->netc_numsecflavors = argp->ex_numsecflavors; @@ -218,9 +212,9 @@ } np->netc_exflags = argp->ex_flags; np->netc_anon = crget(); - np->netc_anon->cr_uid = argp->ex_anon.cr_uid; - crsetgroups(np->netc_anon, argp->ex_anon.cr_ngroups, - argp->ex_anon.cr_groups); + np->netc_anon->cr_uid = argp->ex_uid; + crsetgroups(np->netc_anon, argp->ex_ngroups, + argp->ex_groups); np->netc_anon->cr_prison = &prison0; prison_hold(np->netc_anon->cr_prison); np->netc_numsecflavors = argp->ex_numsecflavors; @@ -512,8 +506,8 @@ */ int -vfs_stdcheckexp(struct mount *mp, struct sockaddr *nam, int *extflagsp, - struct ucred **credanonp, int *numsecflavors, int **secflavors) +vfs_stdcheckexp(struct mount *mp, struct sockaddr *nam, uint64_t *extflagsp, + struct ucred **credanonp, int *numsecflavors, int *secflavors) { struct netcred *np; @@ -534,8 +528,9 @@ KASSERT(*numsecflavors < MAXSECFLAVORS, ("%s: numsecflavors >= MAXSECFLAVORS", __func__)); } - if (secflavors) - *secflavors = np->netc_secflavors; + if (secflavors && np->netc_numsecflavors > 0) + memcpy(secflavors, np->netc_secflavors, np->netc_numsecflavors * + sizeof(int)); lockmgr(&mp->mnt_explock, LK_RELEASE, NULL); return (0); } Index: sys/kern/vfs_init.c =================================================================== --- sys/kern/vfs_init.c +++ sys/kern/vfs_init.c @@ -268,8 +268,8 @@ } static int -vfs_checkexp_sigdefer(struct mount *mp, struct sockaddr *nam, int *exflg, - struct ucred **credp, int *numsecflavors, int **secflavors) +vfs_checkexp_sigdefer(struct mount *mp, struct sockaddr *nam, uint64_t *exflg, + struct ucred **credp, int *numsecflavors, int *secflavors) { int prev_stops, rc; Index: sys/kern/vfs_mount.c =================================================================== --- sys/kern/vfs_mount.c +++ sys/kern/vfs_mount.c @@ -1041,11 +1041,13 @@ ) { struct export_args export; + struct o2export_args o2export; struct vnode *rootvp; void *bufp; struct mount *mp; - int error, export_error, len; + int error, export_error, i, len; uint64_t flag; + gid_t *grps; ASSERT_VOP_ELOCKED(vp, __func__); KASSERT((fsflags & MNT_UPDATE) != 0, ("MNT_UPDATE should be here")); @@ -1128,11 +1130,66 @@ /* Assume that there is only 1 ABI for each length. */ switch (len) { case (sizeof(struct oexport_args)): - bzero(&export, sizeof(export)); + bzero(&o2export, sizeof(o2export)); + o2export.ex_numsecflavors = 1; + o2export.ex_secflavors[0] = AUTH_SYS; /* FALLTHROUGH */ + case (sizeof(o2export)): + bcopy(bufp, &o2export, len); + export.ex_flags = (uint64_t)o2export.ex_flags; + export.ex_root = o2export.ex_root; + export.ex_uid = o2export.ex_anon.cr_uid; + export.ex_groups = NULL; + export.ex_ngroups = o2export.ex_anon.cr_ngroups; + if (export.ex_ngroups > 0) { + if (export.ex_ngroups <= XU_NGROUPS) { + export.ex_groups = malloc( + export.ex_ngroups * sizeof(gid_t), + M_TEMP, M_WAITOK); + for (i = 0; i < export.ex_ngroups; i++) + export.ex_groups[i] = + o2export.ex_anon.cr_groups[i]; + } else + export_error = EINVAL; + } else if (export.ex_ngroups < 0) + export_error = EINVAL; + export.ex_addr = o2export.ex_addr; + export.ex_addrlen = o2export.ex_addrlen; + export.ex_mask = o2export.ex_mask; + export.ex_masklen = o2export.ex_masklen; + export.ex_indexfile = o2export.ex_indexfile; + export.ex_numsecflavors = o2export.ex_numsecflavors; + if (export.ex_numsecflavors < MAXSECFLAVORS) { + for (i = 0; i < export.ex_numsecflavors; i++) + export.ex_secflavors[i] = + o2export.ex_secflavors[i]; + } else + export_error = EINVAL; + if (export_error == 0) + export_error = vfs_export(mp, &export); + free(export.ex_groups, M_TEMP); + break; case (sizeof(export)): bcopy(bufp, &export, len); - export_error = vfs_export(mp, &export); + grps = NULL; + if (export.ex_ngroups > 0) { + if (export.ex_ngroups <= NGROUPS_MAX) { + grps = malloc(export.ex_ngroups * + sizeof(gid_t), M_TEMP, M_WAITOK); + export_error = copyin(export.ex_groups, + grps, export.ex_ngroups * + sizeof(gid_t)); + if (export_error == 0) + export.ex_groups = grps; + } else + export_error = EINVAL; + } else if (export.ex_ngroups == 0) + export.ex_groups = NULL; + else + export_error = EINVAL; + if (export_error == 0) + export_error = vfs_export(mp, &export); + free(grps, M_TEMP); break; default: export_error = EINVAL; @@ -2344,17 +2401,4 @@ error = kernel_mount(ma, flags); return (error); -} - -void -vfs_oexport_conv(const struct oexport_args *oexp, struct export_args *exp) -{ - - bcopy(oexp, exp, sizeof(*oexp)); - if (exp->ex_flags & MNT_EXPORTED) { - exp->ex_numsecflavors = 1; - exp->ex_secflavors[0] = AUTH_SYS; - } else { - exp->ex_numsecflavors = 0; - } } Index: sys/nlm/nlm_prot_impl.c =================================================================== --- sys/nlm/nlm_prot_impl.c +++ sys/nlm/nlm_prot_impl.c @@ -1735,7 +1735,8 @@ nlm_get_vfs_state(struct nlm_host *host, struct svc_req *rqstp, fhandle_t *fhp, struct vfs_state *vs, accmode_t accmode) { - int error, exflags; + int error; + uint64_t exflags; struct ucred *cred = NULL, *credanon = NULL; memset(vs, 0, sizeof(*vs)); Index: sys/sys/mount.h =================================================================== --- sys/sys/mount.h +++ sys/sys/mount.h @@ -494,10 +494,10 @@ }; /* - * Export arguments for local filesystem mount calls. + * Not quite so old export arguments with 32bit ex_flags and xucred ex_anon. */ #define MAXSECFLAVORS 5 -struct export_args { +struct o2export_args { int ex_flags; /* export related flags */ uid_t ex_root; /* mapping for root uid */ struct xucred ex_anon; /* mapping for anonymous user */ @@ -511,6 +511,25 @@ }; /* + * Export arguments for local filesystem mount calls. + */ +#define MAXSECFLAVORS 5 +struct export_args { + uint64_t ex_flags; /* export related flags */ + uid_t ex_root; /* mapping for root uid */ + uid_t ex_uid; /* mapping for anonymous user */ + int ex_ngroups; + gid_t *ex_groups; + struct sockaddr *ex_addr; /* net address to which exported */ + u_char ex_addrlen; /* and the net address length */ + struct sockaddr *ex_mask; /* mask of valid bits in saddr */ + u_char ex_masklen; /* and the smask length */ + char *ex_indexfile; /* index file for WebNFS URLs */ + int ex_numsecflavors; /* security flavor count */ + int ex_secflavors[MAXSECFLAVORS]; /* list of security flavors */ +}; + +/* * Structure holding information for a publicly exported filesystem * (WebNFS). Currently the specs allow just for one such filesystem. */ @@ -689,8 +708,8 @@ typedef int vfs_fhtovp_t(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp); typedef int vfs_checkexp_t(struct mount *mp, struct sockaddr *nam, - int *extflagsp, struct ucred **credanonp, - int *numsecflavors, int **secflavors); + uint64_t *extflagsp, struct ucred **credanonp, + int *numsecflavors, int *secflavors); typedef int vfs_init_t(struct vfsconf *); typedef int vfs_uninit_t(struct vfsconf *); typedef int vfs_extattrctl_t(struct mount *mp, int cmd, @@ -923,8 +942,6 @@ void vfs_mountroot(void); /* mount our root filesystem */ void vfs_mountedfrom(struct mount *, const char *from); void vfs_notify_upper(struct vnode *, int); -void vfs_oexport_conv(const struct oexport_args *oexp, - struct export_args *exp); void vfs_ref(struct mount *); void vfs_rel(struct mount *); struct mount *vfs_mount_alloc(struct vnode *, struct vfsconf *, const char *, Index: sys/ufs/ffs/ffs_vfsops.c =================================================================== --- sys/ufs/ffs/ffs_vfsops.c +++ sys/ufs/ffs/ffs_vfsops.c @@ -589,7 +589,6 @@ ffs_cmount(struct mntarg *ma, void *data, uint64_t flags) { struct ufs_args args; - struct export_args exp; int error; if (data == NULL) @@ -597,10 +596,9 @@ error = copyin(data, &args, sizeof args); if (error) return (error); - vfs_oexport_conv(&args.export, &exp); ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); - ma = mount_arg(ma, "export", &exp, sizeof(exp)); + ma = mount_arg(ma, "export", &args.export, sizeof(args.export)); error = kernel_mount(ma, flags); return (error); Index: usr.sbin/mountd/mountd.c =================================================================== --- usr.sbin/mountd/mountd.c +++ usr.sbin/mountd/mountd.c @@ -112,6 +112,15 @@ #define DP_DEFSET 0x1 #define DP_HOSTSET 0x2 +/* + * maproot/mapall credentials. + */ +struct expcred { + uid_t cr_uid; + int cr_ngroups; + gid_t cr_groups[NGROUPS_MAX + 1]; +}; + struct exportlist { struct dirlist *ex_dirl; struct dirlist *ex_defdir; @@ -120,8 +129,8 @@ fsid_t ex_fs; char *ex_fsdir; char *ex_indexfile; - struct xucred ex_defanon; - int ex_defexflags; + struct expcred ex_defanon; + uint64_t ex_defexflags; int ex_numsecflavors; int ex_secflavors[MAXSECFLAVORS]; int ex_defnumsecflavors; @@ -152,8 +161,8 @@ int gr_type; union grouptypes gr_ptr; struct grouplist *gr_next; - struct xucred gr_anon; - int gr_exflags; + struct expcred gr_anon; + uint64_t gr_exflags; int gr_flag; int gr_numsecflavors; int gr_secflavors[MAXSECFLAVORS]; @@ -194,7 +203,7 @@ static char *add_expdir(struct dirlist **, char *, int); static void add_dlist(struct dirlist **, struct dirlist *, struct grouplist *, int, struct exportlist *, - struct xucred *, int); + struct expcred *, uint64_t); static void add_mlist(char *, char *); static int check_dirpath(char *); static int check_options(struct dirlist *); @@ -208,10 +217,10 @@ static void del_mlist(char *hostp, char *dirp); static struct dirlist *dirp_search(struct dirlist *, char *); static int do_export_mount(struct exportlist *, struct statfs *); -static int do_mount(struct exportlist *, struct grouplist *, int, - struct xucred *, char *, int, struct statfs *, int, int *); +static int do_mount(struct exportlist *, struct grouplist *, uint64_t, + struct expcred *, char *, int, struct statfs *, int, int *); static int do_opt(char **, char **, struct exportlist *, - struct grouplist *, int *, int *, struct xucred *); + struct grouplist *, int *, uint64_t *, struct expcred *); static struct exportlist *ex_search(fsid_t *, struct exportlisthead *); static struct exportlist *get_exp(void); static void free_dir(struct dirlist *); @@ -226,7 +235,7 @@ static void read_exportfile(int); static int compare_nmount_exportlist(struct iovec *, int, char *); static int compare_export(struct exportlist *, struct exportlist *); -static int compare_cred(struct xucred *, struct xucred *); +static int compare_cred(struct expcred *, struct expcred *); static int compare_secflavor(int *, int *, int); static void delete_export(struct iovec *, int, struct statfs *, char *); static int get_host(char *, struct grouplist *, struct grouplist *); @@ -237,13 +246,13 @@ static void getexp_err(struct exportlist *, struct grouplist *, const char *); static struct grouplist *get_grp(void); static void hang_dirp(struct dirlist *, struct grouplist *, - struct exportlist *, int, struct xucred *, int); + struct exportlist *, int, struct expcred *, uint64_t); static void huphandler(int sig); static int makemask(struct sockaddr_storage *ssp, int bitlen); static void mntsrv(struct svc_req *, SVCXPRT *); static void nextfield(char **, char **); static void out_of_mem(void); -static void parsecred(char *, struct xucred *); +static void parsecred(char *, struct expcred *); static int parsesec(char *, struct exportlist *); static int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); @@ -259,6 +268,7 @@ static int xdr_fhs(XDR *, caddr_t); static int xdr_mlist(XDR *, caddr_t); static void terminate(int); +static void cp_cred(struct expcred *, struct expcred *); #define EXPHASH(f) (fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize) static struct exportlisthead *exphead = NULL; @@ -268,13 +278,6 @@ static char *exnames_default[2] = { _PATH_EXPORTS, NULL }; static char **exnames; static char **hosts = NULL; -static struct xucred def_anon = { - XUCRED_VERSION, - (uid_t)65534, - 1, - { (gid_t)65533 }, - { NULL } -}; static int force_v2 = 0; static int resvport_only = 1; static int nhosts = 0; @@ -1503,9 +1506,10 @@ struct grouplist *grp, *tgrp, *savgrp; struct dirlist *dirhead; struct statfs fsb; - struct xucred anon; + struct expcred anon; char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; - int len, has_host, exflags, got_nondir, dirplen, netgrp; + int len, has_host, got_nondir, dirplen, netgrp; + uint64_t exflags; v4root_phase = 0; dirhead = (struct dirlist *)NULL; @@ -1521,7 +1525,9 @@ * Set defaults. */ has_host = FALSE; - anon = def_anon; + anon.cr_uid = 65534; + anon.cr_ngroups = 1; + anon.cr_groups[0] = 65533; exflags = MNT_EXPORTED; got_nondir = 0; opt_flags = 0; @@ -1740,7 +1746,7 @@ grp = tgrp; do { grp->gr_exflags = exflags; - grp->gr_anon = anon; + cp_cred(&grp->gr_anon, &anon); if (v4root_phase == 2 && passno == 0) LOGDEBUG("do_mount v4root"); if (passno == 0 && do_mount(ep, grp, exflags, &anon, @@ -1880,7 +1886,7 @@ */ bzero(&eargs, sizeof (eargs)); eargs.export.ex_flags = MNT_DELEXPORT; - if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && + if (nfssvc(NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT, (caddr_t)&eargs) < 0 && errno != ENOENT) syslog(LOG_ERR, "Can't delete exports for V4:"); @@ -2260,10 +2266,10 @@ } while (0) /* - * Compare to struct xucred's. Return 0 if the same and 1 otherwise. + * Compare two struct expcred's. Return 0 if the same and 1 otherwise. */ static int -compare_cred(struct xucred *cr0, struct xucred *cr1) +compare_cred(struct expcred *cr0, struct expcred *cr1) { if (cr0->cr_uid != cr1->cr_uid || cr0->cr_ngroups != cr1->cr_ngroups) @@ -2429,7 +2435,7 @@ */ static void hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, - int flags, struct xucred *anoncrp, int exflags) + int flags, struct expcred *anoncrp, uint64_t exflags) { struct hostlist *hp; struct dirlist *dp2; @@ -2447,7 +2453,7 @@ if (ep->ex_numsecflavors > 0) memcpy(ep->ex_defsecflavors, ep->ex_secflavors, sizeof(ep->ex_secflavors)); - ep->ex_defanon = *anoncrp; + cp_cred(&ep->ex_defanon, anoncrp); ep->ex_defexflags = exflags; } else while (grp) { hp = get_ht(); @@ -2481,7 +2487,8 @@ */ static void add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, - int flags, struct exportlist *ep, struct xucred *anoncrp, int exflags) + int flags, struct exportlist *ep, struct expcred *anoncrp, + uint64_t exflags) { struct dirlist *dp; struct hostlist *hp; @@ -2530,7 +2537,7 @@ if (ep->ex_numsecflavors > 0) memcpy(ep->ex_defsecflavors, ep->ex_secflavors, sizeof(ep->ex_secflavors)); - ep->ex_defanon = *anoncrp; + cp_cred(&ep->ex_defanon, anoncrp); ep->ex_defexflags = exflags; } } @@ -2702,7 +2709,7 @@ */ static int do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, - int *has_hostp, int *exflagsp, struct xucred *cr) + int *has_hostp, uint64_t *exflagsp, struct expcred *cr) { char *cpoptarg, *cpoptend; char *cp, *endcp, *cpopt, savedc, savedc2; @@ -2964,7 +2971,7 @@ defgrp.gr_type = GT_DEFAULT; defgrp.gr_next = NULL; /* We have an entry for all other hosts/nets. */ - LOGDEBUG("ex_defexflags=0x%x", ep->ex_defexflags); + LOGDEBUG("ex_defexflags=0x%jx", (uintmax_t)ep->ex_defexflags); ret = do_mount(ep, &defgrp, ep->ex_defexflags, &ep->ex_defanon, ep->ex_fsdir, dirlen, fsp, ep->ex_defnumsecflavors, ep->ex_defsecflavors); @@ -2975,8 +2982,8 @@ /* Do a mount for each group. */ grp = ep->ex_grphead; while (grp != NULL) { - LOGDEBUG("do mount gr_type=0x%x gr_exflags=0x%x", - grp->gr_type, grp->gr_exflags); + LOGDEBUG("do mount gr_type=0x%x gr_exflags=0x%jx", + grp->gr_type, (uintmax_t)grp->gr_exflags); ret = do_mount(ep, grp, grp->gr_exflags, &grp->gr_anon, ep->ex_fsdir, dirlen, fsp, grp->gr_numsecflavors, grp->gr_secflavors); @@ -2992,8 +2999,8 @@ * the kernel. */ static int -do_mount(struct exportlist *ep, struct grouplist *grp, int exflags, - struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb, +do_mount(struct exportlist *ep, struct grouplist *grp, uint64_t exflags, + struct expcred *anoncrp, char *dirp, int dirplen, struct statfs *fsb, int numsecflavors, int *secflavors) { struct statfs fsb1; @@ -3019,8 +3026,14 @@ bzero(eap, sizeof (struct export_args)); bzero(errmsg, sizeof(errmsg)); eap->ex_flags = exflags; - eap->ex_anon = *anoncrp; - LOGDEBUG("do_mount exflags=0x%x", exflags); + eap->ex_uid = anoncrp->cr_uid; + eap->ex_ngroups = anoncrp->cr_ngroups; + if (eap->ex_ngroups > 0) { + eap->ex_groups = malloc(eap->ex_ngroups * sizeof(gid_t)); + memcpy(eap->ex_groups, anoncrp->cr_groups, eap->ex_ngroups * + sizeof(gid_t)); + } + LOGDEBUG("do_mount exflags=0x%jx", (uintmax_t)exflags); eap->ex_indexfile = ep->ex_indexfile; if (grp->gr_type == GT_HOST) ai = grp->gr_ptr.gt_addrinfo; @@ -3090,9 +3103,11 @@ */ if (v4root_phase == 2) { nfsea.fspec = v4root_dirpath; - if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) { + if (nfssvc(NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT, + (caddr_t)&nfsea) < 0) { syslog(LOG_ERR, "Exporting V4: failed"); - return (2); + ret = 2; + goto error_exit; } } else { /* @@ -3208,6 +3223,7 @@ if (cp) *cp = savedc; error_exit: + free(eap->ex_groups); /* free strings allocated by strdup() in getmntopts.c */ if (iov != NULL) { free(iov[0].iov_base); /* fstype */ @@ -3434,17 +3450,14 @@ * Parse a description of a credential. */ static void -parsecred(char *namelist, struct xucred *cr) +parsecred(char *namelist, struct expcred *cr) { char *name; int cnt; char *names; struct passwd *pw; struct group *gr; - gid_t groups[XU_NGROUPS + 1]; - int ngroups; - cr->cr_version = XUCRED_VERSION; /* * Set up the unprivileged user. */ @@ -3470,19 +3483,24 @@ return; } cr->cr_uid = pw->pw_uid; - ngroups = XU_NGROUPS + 1; - if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) { + cr->cr_ngroups = NGROUPS_MAX + 1; + if (getgrouplist(pw->pw_name, pw->pw_gid, cr->cr_groups, + &cr->cr_ngroups)) { syslog(LOG_ERR, "too many groups"); - ngroups = XU_NGROUPS + 1; + cr->cr_ngroups = NGROUPS_MAX + 1; } /* * Compress out duplicate. */ - cr->cr_ngroups = ngroups - 1; - cr->cr_groups[0] = groups[0]; - for (cnt = 2; cnt < ngroups; cnt++) - cr->cr_groups[cnt - 1] = groups[cnt]; + if (cr->cr_ngroups > 1 && cr->cr_groups[0] == + cr->cr_groups[1]) { + for (cnt = 2; cnt < cr->cr_ngroups; cnt++) + cr->cr_groups[cnt - 1] = cr->cr_groups[cnt]; + cr->cr_ngroups--; + } + if (cr->cr_ngroups > NGROUPS_MAX) + cr->cr_ngroups = NGROUPS_MAX; return; } /* @@ -3498,7 +3516,7 @@ return; } cr->cr_ngroups = 0; - while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) { + while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS_MAX) { name = strsep_quote(&names, ":"); if (isdigit(*name) || *name == '-') { cr->cr_groups[cr->cr_ngroups++] = atoi(name); @@ -3510,7 +3528,7 @@ cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; } } - if (names != NULL && *names != '\0' && cr->cr_ngroups == XU_NGROUPS) + if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS_MAX) syslog(LOG_ERR, "too many groups"); } @@ -3830,4 +3848,14 @@ rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); exit (0); +} + +static void +cp_cred(struct expcred *outcr, struct expcred *incr) +{ + + outcr->cr_uid = incr->cr_uid; + outcr->cr_ngroups = incr->cr_ngroups; + memcpy(outcr->cr_groups, incr->cr_groups, incr->cr_ngroups * + sizeof(gid_t)); }