X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0a7de7458d150b5d4dffc935ba399be265ef0a1a..eb6b6ca394357805f2bdba989abae309f718b4d8:/bsd/nfs/nfs_vfsops.c diff --git a/bsd/nfs/nfs_vfsops.c b/bsd/nfs/nfs_vfsops.c index 1ac2b3bd5..ef5457410 100644 --- a/bsd/nfs/nfs_vfsops.c +++ b/bsd/nfs/nfs_vfsops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2017 Apple Inc. All rights reserved. + * Copyright (c) 2000-2019 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -64,6 +64,10 @@ * @(#)nfs_vfsops.c 8.12 (Berkeley) 5/20/95 * FreeBSD-Id: nfs_vfsops.c,v 1.52 1997/11/12 05:42:21 julian Exp $ */ + +#include +#if CONFIG_NFS_CLIENT + /* * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce * support for mandatory and extensible security protections. This notice @@ -85,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -178,10 +183,12 @@ int nfs_tprintf_delay = NFS_TPRINTF_DELAY; int mountnfs(char *, mount_t, vfs_context_t, vnode_t *); +#if CONFIG_NETBOOT static int nfs_mount_diskless(struct nfs_dlmount *, const char *, int, vnode_t *, mount_t *, vfs_context_t); #if !defined(NO_MOUNT_PRIVATE) static int nfs_mount_diskless_private(struct nfs_dlmount *, const char *, int, vnode_t *, mount_t *, vfs_context_t); #endif /* NO_MOUNT_PRIVATE */ +#endif int nfs_mount_connect(struct nfsmount *); void nfs_mount_drain_and_cleanup(struct nfsmount *); void nfs_mount_cleanup(struct nfsmount *); @@ -238,47 +245,49 @@ int nfs4_getquota(struct nfsmount *, vfs_context_t, uid_t, int, struct dqblk *); #endif const struct nfs_funcs nfs3_funcs = { - nfs3_mount, - nfs3_update_statfs, - nfs3_getquota, - nfs3_access_rpc, - nfs3_getattr_rpc, - nfs3_setattr_rpc, - nfs3_read_rpc_async, - nfs3_read_rpc_async_finish, - nfs3_readlink_rpc, - nfs3_write_rpc_async, - nfs3_write_rpc_async_finish, - nfs3_commit_rpc, - nfs3_lookup_rpc_async, - nfs3_lookup_rpc_async_finish, - nfs3_remove_rpc, - nfs3_rename_rpc, - nfs3_setlock_rpc, - nfs3_unlock_rpc, - nfs3_getlock_rpc + .nf_mount = nfs3_mount, + .nf_update_statfs = nfs3_update_statfs, + .nf_getquota = nfs3_getquota, + .nf_access_rpc = nfs3_access_rpc, + .nf_getattr_rpc = nfs3_getattr_rpc, + .nf_setattr_rpc = nfs3_setattr_rpc, + .nf_read_rpc_async = nfs3_read_rpc_async, + .nf_read_rpc_async_finish = nfs3_read_rpc_async_finish, + .nf_readlink_rpc = nfs3_readlink_rpc, + .nf_write_rpc_async = nfs3_write_rpc_async, + .nf_write_rpc_async_finish = nfs3_write_rpc_async_finish, + .nf_commit_rpc = nfs3_commit_rpc, + .nf_lookup_rpc_async = nfs3_lookup_rpc_async, + .nf_lookup_rpc_async_finish = nfs3_lookup_rpc_async_finish, + .nf_remove_rpc = nfs3_remove_rpc, + .nf_rename_rpc = nfs3_rename_rpc, + .nf_setlock_rpc = nfs3_setlock_rpc, + .nf_unlock_rpc = nfs3_unlock_rpc, + .nf_getlock_rpc = nfs3_getlock_rpc }; +#if CONFIG_NFS4 const struct nfs_funcs nfs4_funcs = { - nfs4_mount, - nfs4_update_statfs, - nfs4_getquota, - nfs4_access_rpc, - nfs4_getattr_rpc, - nfs4_setattr_rpc, - nfs4_read_rpc_async, - nfs4_read_rpc_async_finish, - nfs4_readlink_rpc, - nfs4_write_rpc_async, - nfs4_write_rpc_async_finish, - nfs4_commit_rpc, - nfs4_lookup_rpc_async, - nfs4_lookup_rpc_async_finish, - nfs4_remove_rpc, - nfs4_rename_rpc, - nfs4_setlock_rpc, - nfs4_unlock_rpc, - nfs4_getlock_rpc + .nf_mount = nfs4_mount, + .nf_update_statfs = nfs4_update_statfs, + .nf_getquota = nfs4_getquota, + .nf_access_rpc = nfs4_access_rpc, + .nf_getattr_rpc = nfs4_getattr_rpc, + .nf_setattr_rpc = nfs4_setattr_rpc, + .nf_read_rpc_async = nfs4_read_rpc_async, + .nf_read_rpc_async_finish = nfs4_read_rpc_async_finish, + .nf_readlink_rpc = nfs4_readlink_rpc, + .nf_write_rpc_async = nfs4_write_rpc_async, + .nf_write_rpc_async_finish = nfs4_write_rpc_async_finish, + .nf_commit_rpc = nfs4_commit_rpc, + .nf_lookup_rpc_async = nfs4_lookup_rpc_async, + .nf_lookup_rpc_async_finish = nfs4_lookup_rpc_async_finish, + .nf_remove_rpc = nfs4_remove_rpc, + .nf_rename_rpc = nfs4_rename_rpc, + .nf_setlock_rpc = nfs4_setlock_rpc, + .nf_unlock_rpc = nfs4_unlock_rpc, + .nf_getlock_rpc = nfs4_getlock_rpc }; +#endif /* * Called once to initialize data structures... @@ -286,8 +295,9 @@ const struct nfs_funcs nfs4_funcs = { int nfs_vfs_init(__unused struct vfsconf *vfsp) { +#if CONFIG_NFS4 int i; - +#endif /* * Check to see if major data structures haven't bloated. */ @@ -328,8 +338,11 @@ nfs_vfs_init(__unused struct vfsconf *vfsp) nfs_nbinit(); /* Init the nfsbuf table */ nfs_nhinit(); /* Init the nfsnode table */ nfs_lockinit(); /* Init the nfs lock state */ +#if CONFIG_NFS_GSS nfs_gss_init(); /* Init RPCSEC_GSS security */ +#endif +#if CONFIG_NFS4 /* NFSv4 stuff */ NFS4_PER_FS_ATTRIBUTES(nfs_fs_attr_bitmap); NFS4_PER_OBJECT_ATTRIBUTES(nfs_object_attr_bitmap); @@ -338,15 +351,18 @@ nfs_vfs_init(__unused struct vfsconf *vfsp) nfs_getattr_bitmap[i] &= nfs_object_attr_bitmap[i]; } TAILQ_INIT(&nfsclientids); +#endif /* initialize NFS timer callouts */ nfs_request_timer_call = thread_call_allocate(nfs_request_timer, NULL); nfs_buf_timer_call = thread_call_allocate(nfs_buf_timer, NULL); +#if CONFIG_NFS4 nfs4_callback_timer_call = thread_call_allocate(nfs4_callback_timer, NULL); - +#endif return 0; } + /* * nfs statfs call */ @@ -434,6 +450,7 @@ nfsmout: return error; } +#if CONFIG_NFS4 int nfs4_update_statfs(struct nfsmount *nmp, vfs_context_t ctx) { @@ -506,16 +523,21 @@ nfsmout: vnode_put(NFSTOV(np)); return error; } +#endif /* CONFIG_NFS4 */ + /* * Return an NFS volume name from the mntfrom name. */ static void -nfs_get_volname(struct mount *mp, char *volname, size_t len) +nfs_get_volname(struct mount *mp, char *volname, size_t len, __unused vfs_context_t ctx) { const char *ptr, *cptr; const char *mntfrom = mp->mnt_vfsstat.f_mntfromname; - size_t mflen = strnlen(mntfrom, MAXPATHLEN + 1); + size_t mflen; + + + mflen = strnlen(mntfrom, MAXPATHLEN + 1); if (mflen > MAXPATHLEN || mflen == 0) { strlcpy(volname, "Bad volname", len); @@ -557,6 +579,7 @@ nfs_get_volname(struct mount *mp, char *volname, size_t len) strlcpy(volname, ptr, len); } + /* * The NFS VFS_GETATTR function: "statfs"-type information is retrieved * using the nf_update_statfs() function, and other attributes are cobbled @@ -646,10 +669,11 @@ nfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t ctx) if (VFSATTR_IS_ACTIVE(fsap, f_vol_name)) { /*%%% IF fail over support is implemented we may need to take nm_lock */ - nfs_get_volname(mp, fsap->f_vol_name, MAXPATHLEN); + nfs_get_volname(mp, fsap->f_vol_name, MAXPATHLEN, ctx); VFSATTR_SET_SUPPORTED(fsap, f_vol_name); } - if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) { + if (VFSATTR_IS_ACTIVE(fsap, f_capabilities) + ) { u_int32_t caps, valid; nfsnode_t np = nmp->nm_dnp; @@ -663,10 +687,10 @@ nfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t ctx) * The capabilities[] array defines what this volume supports. * * The valid[] array defines which bits this code understands - * the meaning of (whether the volume has that capability or not). - * Any zero bits here means "I don't know what you're asking about" - * and the caller cannot tell whether that capability is - * present or not. + * the meaning of (whether the volume has that capability or + * not). Any zero bits here means "I don't know what you're + * asking about" and the caller cannot tell whether that + * capability is present or not. */ caps = valid = 0; if (NFS_BITMAP_ISSET(nmp->nm_fsattr.nfsa_bitmap, NFS_FATTR_SYMLINK_SUPPORT)) { @@ -706,6 +730,7 @@ nfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t ctx) */ caps |= VOL_CAP_FMT_2TB_FILESIZE; } +#if CONFIG_NFS4 if (nfsvers >= NFS_VER4) { caps |= VOL_CAP_FMT_HIDDEN_FILES; valid |= VOL_CAP_FMT_HIDDEN_FILES; @@ -713,6 +738,7 @@ nfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t ctx) // caps |= VOL_CAP_FMT_OPENDENYMODES; // valid |= VOL_CAP_FMT_OPENDENYMODES; } +#endif // no version of nfs supports immutable files caps |= VOL_CAP_FMT_NO_IMMUTABLE_FILES; valid |= VOL_CAP_FMT_NO_IMMUTABLE_FILES; @@ -753,16 +779,18 @@ nfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t ctx) /* * We don't support most of the interfaces. * - * We MAY support locking, but we don't have any easy way of probing. - * We can tell if there's no lockd running or if locks have been - * disabled for a mount, so we can definitely answer NO in that case. - * Any attempt to send a request to lockd to test for locking support - * may cause the lazily-launched locking daemons to be started - * unnecessarily. So we avoid that. However, we do record if we ever - * successfully perform a lock operation on a mount point, so if it - * looks like lock ops have worked, we do report that we support them. + * We MAY support locking, but we don't have any easy way of + * probing. We can tell if there's no lockd running or if + * locks have been disabled for a mount, so we can definitely + * answer NO in that case. Any attempt to send a request to + * lockd to test for locking support may cause the lazily- + * launched locking daemons to be started unnecessarily. So + * we avoid that. However, we do record if we ever successfully + * perform a lock operation on a mount point, so if it looks + * like lock ops have worked, we do report that we support them. */ caps = valid = 0; +#if CONFIG_NFS4 if (nfsvers >= NFS_VER4) { caps = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK; valid = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK; @@ -780,7 +808,9 @@ nfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t ctx) } valid |= VOL_CAP_INT_NAMEDSTREAMS; #endif - } else if (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) { + } else +#endif + if (nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED) { /* locks disabled on this mount, so they definitely won't work */ valid = VOL_CAP_INT_ADVLOCK | VOL_CAP_INT_FLOCK; } else if (nmp->nm_state & NFSSTA_LOCKSWORK) { @@ -980,6 +1010,7 @@ nfsmout: * if swdevt[0].sw_dev == NODEV * - build the rootfs mount point and call mountnfs() to do the rest. */ +#if CONFIG_NETBOOT int nfs_mountroot(void) { @@ -1341,7 +1372,7 @@ nfs_mount_diskless_private( uint32_t argslength_offset, attrslength_offset, end_offset; procp = current_proc(); /* XXX */ - xb_init(&xb, 0); + xb_init(&xb, XDRBUF_NONE); { /* @@ -1592,6 +1623,8 @@ out: } #endif /* NO_MOUNT_PRIVATE */ +#endif + /* * Convert old style NFS mount args to XDR. */ @@ -2158,6 +2191,7 @@ out: return error; } +#if CONFIG_NFS4 /* * Update an NFSv4 mount path with the contents of the symlink. * @@ -2763,6 +2797,7 @@ nfsmout: nfsm_chain_cleanup(&nmrep); return error; } +#endif /* CONFIG_NFS4 */ /* * Thread to handle initial NFS mount connection. @@ -2844,7 +2879,7 @@ nfs_mount_connect(struct nfsmount *nmp) { int error = 0, slpflag; thread_t thd; - struct timespec ts = { 2, 0 }; + struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 }; /* * Set up the socket. Perform initial search for a location/server/address to @@ -2923,7 +2958,13 @@ mountnfs( uint32_t *mflags_mask; uint32_t *mflags; uint32_t argslength, attrslength; - struct nfs_location_index firstloc = { NLI_VALID, 0, 0, 0 }; + uid_t set_owner; + struct nfs_location_index firstloc = { + .nli_flags = NLI_VALID, + .nli_loc = 0, + .nli_serv = 0, + .nli_addr = 0 + }; static const struct nfs_etype nfs_default_etypes = { .count = NFS_MAX_ETYPES, .selected = NFS_MAX_ETYPES, @@ -2931,6 +2972,7 @@ mountnfs( NFS_AES128_CTS_HMAC_SHA1_96, NFS_DES3_CBC_SHA1_KD} }; + /* make sure mbuf constants are set up */ if (!nfs_mbuf_mhlen) { nfs_mbuf_init(); @@ -3003,6 +3045,7 @@ mountnfs( nmp->nm_iodlink.tqe_next = NFSNOLIST; nmp->nm_deadtimeout = 0; nmp->nm_curdeadtimeout = 0; + NFS_BITMAP_SET(nmp->nm_flags, NFS_MFLAG_RDIRPLUS); /* enable RDIRPLUS by default. It will be reverted later in case NFSv2 is used */ NFS_BITMAP_SET(nmp->nm_flags, NFS_MFLAG_NOACL); nmp->nm_realm = NULL; nmp->nm_principal = NULL; @@ -3115,11 +3158,13 @@ mountnfs( switch (val) { case NFS_LOCK_MODE_DISABLED: case NFS_LOCK_MODE_LOCAL: +#if CONFIG_NFS4 if (nmp->nm_vers >= NFS_VER4) { /* disabled/local lock mode only allowed on v2/v3 */ error = EINVAL; break; } +#endif /* FALLTHROUGH */ case NFS_LOCK_MODE_ENABLED: nmp->nm_lockmode = val; @@ -3184,10 +3229,11 @@ mountnfs( xb_get_32(error, &xb, nmp->nm_numgrps); } if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SOCKET_TYPE)) { - char sotype[6]; + char sotype[16]; + *sotype = '\0'; xb_get_32(error, &xb, val); - if (!error && ((val < 3) || (val > 5))) { + if (!error && ((val < 3) || (val > sizeof(sotype)))) { error = EINVAL; } nfsmerr_if(error); @@ -3216,13 +3262,24 @@ mountnfs( nmp->nm_sofamily = AF_INET6; } else if (!strcmp(sotype, "inet")) { nmp->nm_sofamily = 0; /* ok */ + } else if (!strcmp(sotype, "ticotsord")) { + nmp->nm_sofamily = AF_LOCAL; + nmp->nm_sotype = SOCK_STREAM; + } else if (!strcmp(sotype, "ticlts")) { + nmp->nm_sofamily = AF_LOCAL; + nmp->nm_sotype = SOCK_DGRAM; } else { error = EINVAL; } +#if CONFIG_NFS4 if (!error && (nmp->nm_vers >= NFS_VER4) && nmp->nm_sotype && (nmp->nm_sotype != SOCK_STREAM)) { error = EINVAL; /* NFSv4 is only allowed over TCP. */ } +#endif + if (error) { + NFS_VFS_DBG("EINVAL sotype = \"%s\"\n", sotype); + } nfsmerr_if(error); } if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_NFS_PORT)) { @@ -3279,6 +3336,7 @@ mountnfs( xb_get_32(error, &xb, nmp->nm_locations.nl_numlocs); /* fs location count */ /* sanity check location count */ if (!error && ((nmp->nm_locations.nl_numlocs < 1) || (nmp->nm_locations.nl_numlocs > 256))) { + NFS_VFS_DBG("Invalid number of fs_locations: %d", nmp->nm_locations.nl_numlocs); error = EINVAL; } nfsmerr_if(error); @@ -3296,12 +3354,14 @@ mountnfs( xb_get_32(error, &xb, fsl->nl_servcount); /* server count */ /* sanity check server count */ if (!error && ((fsl->nl_servcount < 1) || (fsl->nl_servcount > 256))) { + NFS_VFS_DBG("Invalid server count %d", fsl->nl_servcount); error = EINVAL; } nfsmerr_if(error); MALLOC(fsl->nl_servers, struct nfs_fs_server **, fsl->nl_servcount * sizeof(struct nfs_fs_server*), M_TEMP, M_WAITOK | M_ZERO); if (!fsl->nl_servers) { error = ENOMEM; + NFS_VFS_DBG("Server count = %d, error = %d\n", fsl->nl_servcount, error); } for (serv = 0; serv < fsl->nl_servcount; serv++) { nfsmerr_if(error); @@ -3312,7 +3372,8 @@ mountnfs( fsl->nl_servers[serv] = fss; xb_get_32(error, &xb, val); /* server name length */ /* sanity check server name length */ - if (!error && ((val < 1) || (val > MAXPATHLEN))) { + if (!error && (val > MAXPATHLEN)) { + NFS_VFS_DBG("Invalid server name length %d", val); error = EINVAL; } nfsmerr_if(error); @@ -3325,6 +3386,7 @@ mountnfs( xb_get_32(error, &xb, fss->ns_addrcount); /* address count */ /* sanity check address count (OK to be zero) */ if (!error && (fss->ns_addrcount > 256)) { + NFS_VFS_DBG("Invalid address count %d", fss->ns_addrcount); error = EINVAL; } nfsmerr_if(error); @@ -3336,7 +3398,8 @@ mountnfs( for (addr = 0; addr < fss->ns_addrcount; addr++) { xb_get_32(error, &xb, val); /* address length */ /* sanity check address length */ - if (!error && ((val < 1) || (val > 128))) { + if (!error && val > 128) { + NFS_VFS_DBG("Invalid address length %d", val); error = EINVAL; } nfsmerr_if(error); @@ -3356,6 +3419,7 @@ mountnfs( xb_get_32(error, &xb, fsp->np_compcount); /* component count */ /* sanity check component count */ if (!error && (fsp->np_compcount > MAXPATHLEN)) { + NFS_VFS_DBG("Invalid component count %d", fsp->np_compcount); error = EINVAL; } nfsmerr_if(error); @@ -3383,6 +3447,7 @@ mountnfs( continue; } if (!error && ((val < 1) || (val > MAXPATHLEN))) { + NFS_VFS_DBG("Invalid component path length %d", val); error = EINVAL; } nfsmerr_if(error); @@ -3394,7 +3459,8 @@ mountnfs( error = xb_get_bytes(&xb, fsp->np_components[comp], val, 0); /* component */ } xb_get_32(error, &xb, val); /* fs location info length */ - xb_skip(error, &xb, val); /* skip fs location info */ + NFS_VFS_DBG("Skipping fs location info bytes %d", val); + xb_skip(error, &xb, xdr_rndup(val)); /* skip fs location info */ } } if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MNTFLAGS)) { @@ -3466,6 +3532,62 @@ mountnfs( } nfsmerr_if(error); + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_NFS_PORT)) { + if (nmp->nm_nfsport) { + error = EINVAL; + NFS_VFS_DBG("Can't have ports specified over incompatible socket families"); + } + nfsmerr_if(error); + xb_get_32(error, &xb, len); + if (!error && ((len < 1) || (len > sizeof(((struct sockaddr_un *)0)->sun_path)))) { + error = EINVAL; + } + nfsmerr_if(error); + MALLOC(nmp->nm_nfs_localport, char *, len + 1, M_TEMP, M_WAITOK | M_ZERO); + if (!nmp->nm_nfs_localport) { + error = ENOMEM; + } + nfsmerr_if(error); + error = xb_get_bytes(&xb, nmp->nm_nfs_localport, len, 0); + nmp->nm_sofamily = AF_LOCAL; + nmp->nm_nfsport = 1; /* We use the now deprecated tpcmux port to indcate that we have an AF_LOCAL port */ + NFS_VFS_DBG("Setting nfs local port %s (%d)\n", nmp->nm_nfs_localport, nmp->nm_nfsport); + } + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_MOUNT_PORT)) { + if (nmp->nm_mountport) { + error = EINVAL; + NFS_VFS_DBG("Can't have ports specified over mulitple socket families"); + } + nfsmerr_if(error); + xb_get_32(error, &xb, len); + if (!error && ((len < 1) || (len > sizeof(((struct sockaddr_un *)0)->sun_path)))) { + error = EINVAL; + } + nfsmerr_if(error); + MALLOC(nmp->nm_mount_localport, char *, len + 1, M_TEMP, M_WAITOK | M_ZERO); + if (!nmp->nm_mount_localport) { + error = ENOMEM; + } + nfsmerr_if(error); + error = xb_get_bytes(&xb, nmp->nm_mount_localport, len, 0); + nmp->nm_sofamily = AF_LOCAL; + nmp->nm_mountport = 1; /* We use the now deprecated tpcmux port to indcate that we have an AF_LOCAL port */ + NFS_VFS_DBG("Setting mount local port %s (%d)\n", nmp->nm_mount_localport, nmp->nm_mountport); + } + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SET_MOUNT_OWNER)) { + xb_get_32(error, &xb, set_owner); + nfsmerr_if(error); + error = vfs_context_suser(ctx); + /* + * root can set owner to whatever, user can set owner to self + */ + if ((error) && (set_owner == kauth_cred_getuid(vfs_context_ucred(ctx)))) { + /* ok for non-root can set owner to self */ + error = 0; + } + nfsmerr_if(error); + } + /* * Sanity check/finalize settings. */ @@ -3498,10 +3620,11 @@ mountnfs( } nfsmerr_if(error); - /* init mount's mntfromname to first location */ if (!NM_OMATTR_GIVEN(nmp, MNTFROM)) { + /* init mount's mntfromname to first location */ nfs_location_mntfromname(&nmp->nm_locations, firstloc, - vfs_statfs(mp)->f_mntfromname, sizeof(vfs_statfs(mp)->f_mntfromname), 0); + vfs_statfs(mp)->f_mntfromname, + sizeof(vfs_statfs(mp)->f_mntfromname), 0); } /* Need to save the mounting credential for v4. */ @@ -3520,21 +3643,29 @@ mountnfs( } nfsmerr_if(error); - /* do mount's initial socket connection */ - error = nfs_mount_connect(nmp); - nfsmerr_if(error); - /* set up the version-specific function tables */ if (nmp->nm_vers < NFS_VER4) { nmp->nm_funcs = &nfs3_funcs; } else { +#if CONFIG_NFS4 nmp->nm_funcs = &nfs4_funcs; +#else + /* don't go any further if we don't support NFS4 */ + nmp->nm_funcs = NULL; + error = ENOTSUP; + nfsmerr_if(error); +#endif } + /* do mount's initial socket connection */ + error = nfs_mount_connect(nmp); + nfsmerr_if(error); + /* sanity check settings now that version/connection is set */ if (nmp->nm_vers == NFS_VER2) { /* ignore RDIRPLUS on NFSv2 */ NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_RDIRPLUS); } +#if CONFIG_NFS4 if (nmp->nm_vers >= NFS_VER4) { if (NFS_BITMAP_ISSET(nmp->nm_flags, NFS_MFLAG_ACLONLY)) { /* aclonly trumps noacl */ NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOACL); @@ -3544,12 +3675,15 @@ mountnfs( error = EINVAL; /* disabled/local lock mode only allowed on v2/v3 */ } } else { - /* ignore these if not v4 */ - NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOCALLBACK); - NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NAMEDATTR); - NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOACL); - NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_ACLONLY); - } +#endif + /* ignore these if not v4 */ + NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOCALLBACK); + NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NAMEDATTR); + NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_NOACL); + NFS_BITMAP_CLR(nmp->nm_flags, NFS_MFLAG_ACLONLY); +#if CONFIG_NFS4 +} +#endif nfsmerr_if(error); if (nmp->nm_sotype == SOCK_DGRAM) { @@ -3597,6 +3731,19 @@ mountnfs( TAILQ_INIT(&nmp->nm_cwndq); } + if (nmp->nm_saddr->sa_family == AF_LOCAL) { + struct sockaddr_un *un = (struct sockaddr_un *)nmp->nm_saddr; + size_t size; + int n = snprintf(vfs_statfs(mp)->f_mntfromname, sizeof(vfs_statfs(mp)->f_mntfromname), "<%s>:", un->sun_path); + + if (n > 0 && (size_t)n < sizeof(vfs_statfs(mp)->f_mntfromname)) { + size = sizeof(vfs_statfs(mp)->f_mntfromname) - n; + nfs_location_mntfromname(&nmp->nm_locations, firstloc, + &vfs_statfs(mp)->f_mntfromname[n], size, 1); + } + } + + /* * Get the root node/attributes from the NFS server and * do any basic, version-specific setup. @@ -3612,6 +3759,8 @@ mountnfs( */ nmp->nm_dnp = np; *vpp = NFSTOV(np); + + /* get usecount and drop iocount */ error = vnode_ref(*vpp); vnode_put(*vpp); @@ -3643,6 +3792,10 @@ mountnfs( sbp->f_ffree = nmp->nm_fsattr.nfsa_files_free; sbp->f_iosize = nfs_iosize; + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SET_MOUNT_OWNER)) { + sbp->f_owner = set_owner; + } + /* * Calculate the size used for I/O buffers. Use the larger * of the two sizes to minimise NFS requests but make sure @@ -3652,18 +3805,15 @@ mountnfs( * buffers into multiple requests if the buffer size is * larger than the I/O size. */ -#ifndef CONFIG_EMBEDDED iosize = max(nmp->nm_rsize, nmp->nm_wsize); if (iosize < PAGE_SIZE) { iosize = PAGE_SIZE; } -#else - iosize = PAGE_SIZE; -#endif nmp->nm_biosize = trunc_page_32(iosize); /* For NFSv3 and greater, there is a (relatively) reliable ACCESS call. */ - if (nmp->nm_vers > NFS_VER2) { + if (nmp->nm_vers > NFS_VER2 && !NMFLAG(nmp, NOOPAQUE_AUTH) + ) { vfs_setauthopaqueaccess(mp); } @@ -3681,6 +3831,7 @@ mountnfs( break; } + /* success! */ lck_mtx_lock(&nmp->nm_lock); nmp->nm_state |= NFSSTA_MOUNTED; @@ -3704,7 +3855,9 @@ int nfs_mirror_mount_domount(vnode_t dvp, vnode_t vp, vfs_context_t ctx) { nfsnode_t np = VTONFS(vp); +#if CONFIG_NFS4 nfsnode_t dnp = VTONFS(dvp); +#endif struct nfsmount *nmp = NFSTONMP(np); char fstype[MFSTYPENAMELEN], *mntfromname = NULL, *path = NULL, *relpath, *p, *cp; int error = 0, pathbuflen = MAXPATHLEN, i, mntflags = 0, referral, skipcopy = 0; @@ -3725,7 +3878,7 @@ nfs_mirror_mount_domount(vnode_t dvp, vnode_t vp, vfs_context_t ctx) bzero(&nfsls, sizeof(nfsls)); } - xb_init(&xbnew, 0); + xb_init(&xbnew, XDRBUF_NONE); if (!nmp || (nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD))) { return ENXIO; @@ -3793,13 +3946,16 @@ nfs_mirror_mount_domount(vnode_t dvp, vnode_t vp, vfs_context_t ctx) const char *vname = vnode_getname(NFSTOV(np)); if (!vname) { error = ENOENT; - } else { + } +#if CONFIG_NFS4 + else { error = nfs4_get_fs_locations(nmp, dnp, NULL, 0, vname, ctx, &nfsls); vnode_putname(vname); if (!error && (nfsls.nl_numlocs < 1)) { error = ENOENT; } } +#endif nfsmerr_if(error); } @@ -3841,12 +3997,13 @@ nfs_mirror_mount_domount(vnode_t dvp, vnode_t vp, vfs_context_t ctx) } if (referral) { NFS_BITMAP_SET(newmattrs, NFS_MATTR_FS_LOCATIONS); + NFS_BITMAP_CLR(newmattrs, NFS_MATTR_MNTFROM); } else { NFS_BITMAP_SET(newmattrs, NFS_MATTR_FH); } NFS_BITMAP_SET(newmattrs, NFS_MATTR_FLAGS); NFS_BITMAP_SET(newmattrs, NFS_MATTR_MNTFLAGS); - NFS_BITMAP_CLR(newmattrs, NFS_MATTR_MNTFROM); + NFS_BITMAP_SET(newmattrs, NFS_MATTR_SET_MOUNT_OWNER); xb_add_bitmap(error, &xbnew, newmattrs, NFS_MATTR_BITMAP_LEN); attrslength_offset = xb_offset(&xbnew); xb_copy_32(error, &xb, &xbnew, val); /* attrs length */ @@ -3980,20 +4137,18 @@ nfs_mirror_mount_domount(vnode_t dvp, vnode_t vp, vfs_context_t ctx) xb_copy_opaque(error, &xb, &xbnew); /* component */ } /* add additional components */ - for (comp = 0; !skipcopy && !error && (comp < relpathcomps); comp++) { - p = relpath; - while (*p && (*p == '/')) { + p = relpath; + while (*p && (*p == '/')) { + p++; + } + while (*p && !error) { + cp = p; + while (*p && (*p != '/')) { p++; } - while (*p && !error) { - cp = p; - while (*p && (*p != '/')) { - p++; - } - xb_add_string(error, &xbnew, cp, (p - cp)); /* component */ - while (*p && (*p == '/')) { - p++; - } + xb_add_string(error, &xbnew, cp, (p - cp)); /* component */ + while (*p && (*p == '/')) { + p++; } } xb_copy_opaque(error, &xb, &xbnew); /* fs location info */ @@ -4070,6 +4225,31 @@ nfs_mirror_mount_domount(vnode_t dvp, vnode_t vp, vfs_context_t ctx) error = xb_add_bytes(&xbnew, buf, count, 1); } } + /* + * The following string copies rely on the fact that we already validated + * these data when creating the initial mount point. + */ + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_REALM)) { + xb_add_string(error, &xbnew, nmp->nm_realm, strlen(nmp->nm_realm)); + } + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_PRINCIPAL)) { + xb_add_string(error, &xbnew, nmp->nm_principal, strlen(nmp->nm_principal)); + } + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SVCPRINCIPAL)) { + xb_add_string(error, &xbnew, nmp->nm_sprinc, strlen(nmp->nm_sprinc)); + } + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_NFS_PORT)) { + xb_add_string(error, &xbnew, nmp->nm_nfs_localport, strlen(nmp->nm_nfs_localport)); + } + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_MOUNT_PORT)) { + xb_add_string(error, &xbnew, nmp->nm_mount_localport, strlen(nmp->nm_mount_localport)); + } + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SET_MOUNT_OWNER)) { + /* drop embedded owner value */ + xb_get_32(error, &xb, count); + } + /* New mount always gets same owner as this mount */ + xb_add_32(error, &xbnew, vnode_mount(vp)->mnt_vfsstat.f_owner); xb_build_done(error, &xbnew); /* update opaque counts */ @@ -4088,10 +4268,13 @@ nfs_mirror_mount_domount(vnode_t dvp, vnode_t vp, vfs_context_t ctx) /* * For kernel_mount() call, use the existing mount flags (instead of the * original flags) because flags like MNT_NOSUID and MNT_NODEV may have - * been silently enforced. + * been silently enforced. Also, in terms of MACF, the _kernel_ is + * performing the mount (and enforcing all of the mount options), so we + * use the kernel context for the mount call. */ mntflags = vnode_vfsvisflags(vp); mntflags |= (MNT_AUTOMOUNTED | MNT_DONTBROWSE); + ctx = vfs_context_kernel(); /* do the mount */ error = kernel_mount(fstype, dvp, vp, path, xb_buffer_base(&xbnew), argslength, @@ -4122,6 +4305,7 @@ nfsmerr: /* * trigger vnode functions */ +#define NFS_TRIGGER_DEBUG 1 resolver_result_t nfs_mirror_mount_trigger_resolve( @@ -4132,9 +4316,10 @@ nfs_mirror_mount_trigger_resolve( __unused void *data, vfs_context_t ctx) { - nfsnode_t np = VTONFS(vp); - vnode_t pvp = NULLVP; - int error = 0; + nfsnode_t np = VTONFS(vp); + vnode_t pvp = NULLVP; + int error = 0; + int didBusy = 0; resolver_result_t result; /* @@ -4204,6 +4389,21 @@ nfs_mirror_mount_trigger_resolve( #endif return result; } + didBusy = 1; + + /* Check again, in case the mount happened while we were setting busy */ + if (vnode_mountedhere(vp) != NULL) { + /* Been there. Done that. Let's just say it succeeded. */ + error = 0; + goto skipmount; + } + nfs_node_lock_force(np); + if (np->n_flag & NDISARMTRIGGER) { + error = ECANCELED; + nfs_node_unlock(np); + goto skipmount; + } + nfs_node_unlock(np); pvp = vnode_getparent(vp); if (pvp == NULLVP) { @@ -4226,7 +4426,9 @@ skipmount: if (pvp != NULLVP) { vnode_put(pvp); } - nfs_node_clear_busy(np); + if (didBusy) { + nfs_node_clear_busy(np); + } return result; } @@ -4326,7 +4528,8 @@ nfs_ephemeral_mount_harvester_callback(mount_t mp, void *arg) return VFS_RETURNED; } nmp = VFSTONFS(mp); - if (!nmp || !NMFLAG(nmp, EPHEMERAL)) { + if (!nmp || !NMFLAG(nmp, EPHEMERAL) + ) { return VFS_RETURNED; } hinfo->mountcount++; @@ -4438,6 +4641,7 @@ nfs3_mount_rpc(struct nfsmount *nmp, struct sockaddr *sa, int sotype, int nfsver uint32_t mntvers, mntport, val; struct sockaddr_storage ss; struct sockaddr *saddr = (struct sockaddr*)&ss; + struct sockaddr_un *sun = (struct sockaddr_un*)saddr; nfsm_chain_null(&nmreq); nfsm_chain_null(&nmrep); @@ -4452,20 +4656,26 @@ nfs3_mount_rpc(struct nfsmount *nmp, struct sockaddr *sa, int sotype, int nfsver ((struct sockaddr_in*)saddr)->sin_port = htons(nmp->nm_mountport); } mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port); - } else { + } else if (saddr->sa_family == AF_INET6) { if (nmp->nm_mountport) { ((struct sockaddr_in6*)saddr)->sin6_port = htons(nmp->nm_mountport); } mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port); + } else { /* Local domain socket */ + mntport = ((struct sockaddr_un *)saddr)->sun_path[0]; /* Do we have and address? */ + mntproto = IPPROTO_TCP; /* XXX rpcbind only listens on streams sockets for now */ } while (!mntport) { - error = nfs_portmap_lookup(nmp, ctx, saddr, NULL, RPCPROG_MNT, mntvers, mntproto, timeo); + error = nfs_portmap_lookup(nmp, ctx, saddr, NULL, RPCPROG_MNT, mntvers, + mntproto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM, timeo); nfsmout_if(error); if (saddr->sa_family == AF_INET) { mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port); - } else { + } else if (saddr->sa_family == AF_INET6) { mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port); + } else if (saddr->sa_family == AF_LOCAL) { + mntport = ((struct sockaddr_un*)saddr)->sun_path[0]; } if (!mntport) { /* if not found and TCP, then retry with UDP */ @@ -4475,6 +4685,9 @@ nfs3_mount_rpc(struct nfsmount *nmp, struct sockaddr *sa, int sotype, int nfsver } mntproto = IPPROTO_UDP; bcopy(sa, saddr, min(sizeof(ss), sa->sa_len)); + if (saddr->sa_family == AF_LOCAL) { + strlcpy(sun->sun_path, RPCB_TICLTS_PATH, sizeof(sun->sun_path)); + } } } nfsmout_if(error || !mntport); @@ -4541,8 +4754,10 @@ nfs3_umount_rpc(struct nfsmount *nmp, vfs_context_t ctx, int timeo) bcopy(nmp->nm_saddr, saddr, min(sizeof(ss), nmp->nm_saddr->sa_len)); if (saddr->sa_family == AF_INET) { ((struct sockaddr_in*)saddr)->sin_port = htons(mntport); - } else { + } else if (saddr->sa_family == AF_INET6) { ((struct sockaddr_in6*)saddr)->sin6_port = htons(mntport); + } else { /* Local domain socket */ + mntport = ((struct sockaddr_un *)saddr)->sun_path[0]; /* Do we have and address? */ } while (!mntport) { @@ -4550,8 +4765,10 @@ nfs3_umount_rpc(struct nfsmount *nmp, vfs_context_t ctx, int timeo) nfsmout_if(error); if (saddr->sa_family == AF_INET) { mntport = ntohs(((struct sockaddr_in*)saddr)->sin_port); - } else { + } else if (saddr->sa_family == AF_INET6) { mntport = ntohs(((struct sockaddr_in6*)saddr)->sin6_port); + } else { /* Local domain socket */ + mntport = ((struct sockaddr_un *)saddr)->sun_path[0]; /* Do we have and address? */ } /* if not found and mntvers > VER1, then retry with VER1 */ if (!mntport) { @@ -4603,7 +4820,7 @@ nfs_vfs_unmount( struct nfsmount *nmp; vnode_t vp; int error, flags = 0; - struct timespec ts = { 1, 0 }; + struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 }; nmp = VFSTONFS(mp); lck_mtx_lock(&nmp->nm_lock); @@ -4774,7 +4991,7 @@ nfs_mount_zombie(struct nfsmount *nmp, int nm_state_flags) { struct nfsreq *req, *treq; struct nfs_reqqhead iodq, resendq; - struct timespec ts = { 1, 0 }; + struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 }; struct nfs_open_owner *noop, *nextnoop; nfsnode_t np; int docallback; @@ -4783,14 +5000,16 @@ nfs_mount_zombie(struct nfsmount *nmp, int nm_state_flags) nmp->nm_state |= nm_state_flags; nmp->nm_ref++; lck_mtx_unlock(&nmp->nm_lock); - +#if CONFIG_NFS4 /* stop callbacks */ if ((nmp->nm_vers >= NFS_VER4) && !NMFLAG(nmp, NOCALLBACK) && nmp->nm_cbid) { nfs4_mount_callback_shutdown(nmp); } - +#endif +#if CONFIG_NFS_GSS /* Destroy any RPCSEC_GSS contexts */ nfs_gss_clnt_ctx_unmount(nmp); +#endif /* mark the socket for termination */ lck_mtx_lock(&nmp->nm_lock); @@ -4814,6 +5033,7 @@ nfs_mount_zombie(struct nfsmount *nmp, int nm_state_flags) lck_mtx_lock(&nmp->nm_lock); +#if CONFIG_NFS4 if ((nmp->nm_vers >= NFS_VER4) && !NMFLAG(nmp, NOCALLBACK) && nmp->nm_cbid) { /* clear out any pending delegation return requests */ while ((np = TAILQ_FIRST(&nmp->nm_dreturnq))) { @@ -4828,7 +5048,7 @@ nfs_mount_zombie(struct nfsmount *nmp, int nm_state_flags) thread_call_free(nmp->nm_renew_timer); nmp->nm_renew_timer = NULL; } - +#endif lck_mtx_unlock(&nmp->nm_lock); if (nmp->nm_state & NFSSTA_MOUNTED) { @@ -4846,6 +5066,7 @@ nfs_mount_zombie(struct nfsmount *nmp, int nm_state_flags) } } +#if CONFIG_NFS4 if ((nmp->nm_vers >= NFS_VER4) && nmp->nm_longid) { /* remove/deallocate the client ID data */ lck_mtx_lock(nfs_global_mutex); @@ -4857,7 +5078,7 @@ nfs_mount_zombie(struct nfsmount *nmp, int nm_state_flags) nmp->nm_longid = NULL; lck_mtx_unlock(nfs_global_mutex); } - +#endif /* * Be sure all requests for this mount are completed * and removed from the resend queue. @@ -4967,6 +5188,7 @@ nfs_mount_zombie(struct nfsmount *nmp, int nm_state_flags) } lck_mtx_unlock(&nmp->nm_lock); +#if CONFIG_NFS4 /* clean up NFSv4 state */ if (nmp->nm_vers >= NFS_VER4) { lck_mtx_lock(&nmp->nm_lock); @@ -4976,7 +5198,7 @@ nfs_mount_zombie(struct nfsmount *nmp, int nm_state_flags) } lck_mtx_unlock(&nmp->nm_lock); } - +#endif nfs_mount_rele(nmp); } @@ -5042,6 +5264,8 @@ nfs_mount_cleanup(struct nfsmount *nmp) if (nmp->nm_fh) { FREE(nmp->nm_fh, M_TEMP); } + + FREE_ZONE(nmp, sizeof(struct nfsmount), M_NFSMNT); } @@ -5130,13 +5354,13 @@ nfs3_getquota(struct nfsmount *nmp, vfs_context_t ctx, uid_t id, int type, struc uint32_t val = 0, bsize = 0; struct sockaddr *rqsaddr; struct timeval now; - struct timespec ts = { 1, 0 }; + struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 }; if (!nmp->nm_saddr) { return ENXIO; } - if (NMFLAG(nmp, NOQUOTA)) { + if (NMFLAG(nmp, NOQUOTA) || nmp->nm_saddr->sa_family == AF_LOCAL /* XXX for now */) { return ENOTSUP; } @@ -5291,7 +5515,7 @@ nfsmout: nfsm_chain_cleanup(&nmrep); return error; } - +#if CONFIG_NFS4 int nfs4_getquota(struct nfsmount *nmp, vfs_context_t ctx, uid_t id, int type, struct dqblk *dqb) { @@ -5382,7 +5606,7 @@ nfsmout: kauth_cred_unref(&cred); return error; } - +#endif /* CONFIG_NFS4 */ int nfs_vfs_quotactl(mount_t mp, int cmds, uid_t uid, caddr_t datap, vfs_context_t ctx) { @@ -5554,7 +5778,7 @@ int nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb) { struct xdrbuf xbinfo, xborig; - char sotype[6]; + char sotype[16]; uint32_t origargsvers, origargslength; uint32_t infolength_offset, curargsopaquelength_offset, curargslength_offset, attrslength_offset, curargs_end_offset, end_offset; uint32_t miattrs[NFS_MIATTR_BITMAP_LEN]; @@ -5598,9 +5822,11 @@ nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb) NFS_BITMAP_ZERO(mattrs, NFS_MATTR_BITMAP_LEN); NFS_BITMAP_SET(mattrs, NFS_MATTR_FLAGS); NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_VERSION); +#if CONFIG_NFS4 if (nmp->nm_vers >= NFS_VER4) { NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_MINOR_VERSION); } +#endif NFS_BITMAP_SET(mattrs, NFS_MATTR_READ_SIZE); NFS_BITMAP_SET(mattrs, NFS_MATTR_WRITE_SIZE); NFS_BITMAP_SET(mattrs, NFS_MATTR_READDIR_SIZE); @@ -5616,8 +5842,10 @@ nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb) } NFS_BITMAP_SET(mattrs, NFS_MATTR_MAX_GROUP_LIST); NFS_BITMAP_SET(mattrs, NFS_MATTR_SOCKET_TYPE); - NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_PORT); - if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mountport) { + if (nmp->nm_saddr->sa_family != AF_LOCAL) { + NFS_BITMAP_SET(mattrs, NFS_MATTR_NFS_PORT); + } + if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mountport && !nmp->nm_mount_localport) { NFS_BITMAP_SET(mattrs, NFS_MATTR_MOUNT_PORT); } NFS_BITMAP_SET(mattrs, NFS_MATTR_REQUEST_TIMEOUT); @@ -5644,6 +5872,12 @@ nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb) if (nmp->nm_sprinc) { NFS_BITMAP_SET(mattrs, NFS_MATTR_SVCPRINCIPAL); } + if (nmp->nm_nfs_localport) { + NFS_BITMAP_SET(mattrs, NFS_MATTR_LOCAL_NFS_PORT); + } + if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mount_localport) { + NFS_BITMAP_SET(mattrs, NFS_MATTR_LOCAL_MOUNT_PORT); + } /* set up current mount flags bitmap */ /* first set the flags that we will be setting - either on OR off */ @@ -5663,6 +5897,7 @@ nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb) } NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NONEGNAMECACHE); NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_MUTEJUKEBOX); +#if CONFIG_NFS4 if (nmp->nm_vers >= NFS_VER4) { NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_EPHEMERAL); NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOCALLBACK); @@ -5670,6 +5905,7 @@ nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb) NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOACL); NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_ACLONLY); } +#endif NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NFC); NFS_BITMAP_SET(mflags_mask, NFS_MFLAG_NOQUOTA); if (nmp->nm_vers < NFS_VER4) { @@ -5705,6 +5941,7 @@ nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb) if (NMFLAG(nmp, MUTEJUKEBOX)) { NFS_BITMAP_SET(mflags, NFS_MFLAG_MUTEJUKEBOX); } +#if CONFIG_NFS4 if (nmp->nm_vers >= NFS_VER4) { if (NMFLAG(nmp, EPHEMERAL)) { NFS_BITMAP_SET(mflags, NFS_MFLAG_EPHEMERAL); @@ -5722,6 +5959,7 @@ nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb) NFS_BITMAP_SET(mflags, NFS_MFLAG_ACLONLY); } } +#endif if (NMFLAG(nmp, NFC)) { NFS_BITMAP_SET(mflags, NFS_MFLAG_NFC); } @@ -5765,9 +6003,11 @@ nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb) xb_add_bitmap(error, &xbinfo, mflags_mask, NFS_MFLAG_BITMAP_LEN); xb_add_bitmap(error, &xbinfo, mflags, NFS_MFLAG_BITMAP_LEN); xb_add_32(error, &xbinfo, nmp->nm_vers); /* NFS_VERSION */ +#if CONFIG_NFS4 if (nmp->nm_vers >= NFS_VER4) { xb_add_32(error, &xbinfo, nmp->nm_minor_vers); /* NFS_MINOR_VERSION */ } +#endif xb_add_32(error, &xbinfo, nmp->nm_rsize); /* READ_SIZE */ xb_add_32(error, &xbinfo, nmp->nm_wsize); /* WRITE_SIZE */ xb_add_32(error, &xbinfo, nmp->nm_readdirsize); /* READDIR_SIZE */ @@ -5807,13 +6047,29 @@ nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb) } xb_add_32(error, &xbinfo, nmp->nm_numgrps); /* MAX_GROUP_LIST */ nfsmerr_if(error); - snprintf(sotype, sizeof(sotype), "%s%s", (nmp->nm_sotype == SOCK_DGRAM) ? "udp" : "tcp", - nmp->nm_sofamily ? (nmp->nm_sofamily == AF_INET) ? "4" : "6" : ""); - xb_add_string(error, &xbinfo, sotype, strlen(sotype)); /* SOCKET_TYPE */ - xb_add_32(error, &xbinfo, ntohs(((struct sockaddr_in*)nmp->nm_saddr)->sin_port)); /* NFS_PORT */ - if ((nmp->nm_vers < NFS_VER4) && nmp->nm_mountport) { - xb_add_32(error, &xbinfo, nmp->nm_mountport); /* MOUNT_PORT */ + + switch (nmp->nm_saddr->sa_family) { + case AF_INET: + case AF_INET6: + snprintf(sotype, sizeof(sotype), "%s%s", (nmp->nm_sotype == SOCK_DGRAM) ? "udp" : "tcp", + nmp->nm_sofamily ? (nmp->nm_sofamily == AF_INET) ? "4" : "6" : ""); + xb_add_string(error, &xbinfo, sotype, strlen(sotype)); /* SOCKET_TYPE */ + xb_add_32(error, &xbinfo, ntohs(((struct sockaddr_in*)nmp->nm_saddr)->sin_port)); /* NFS_PORT */ + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_MOUNT_PORT)) { + xb_add_32(error, &xbinfo, nmp->nm_mountport); /* MOUNT_PORT */ + } + break; + case AF_LOCAL: + strlcpy(sotype, (nmp->nm_sotype == SOCK_DGRAM) ? "ticlts" : "ticotsord", sizeof(sotype)); + xb_add_string(error, &xbinfo, sotype, strlen(sotype)); + break; + default: + NFS_VFS_DBG("Unsupported address family %d\n", nmp->nm_saddr->sa_family); + printf("Unsupported address family %d\n", nmp->nm_saddr->sa_family); + error = EINVAL; + break; } + timeo = (nmp->nm_timeo * 10) / NFS_HZ; xb_add_32(error, &xbinfo, timeo / 10); /* REQUEST_TIMEOUT */ xb_add_32(error, &xbinfo, (timeo % 10) * 100000000); /* REQUEST_TIMEOUT */ @@ -5861,7 +6117,13 @@ nfs_mountinfo_assemble(struct nfsmount *nmp, struct xdrbuf *xb) if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_SVCPRINCIPAL)) { xb_add_string(error, &xbinfo, nmp->nm_sprinc, strlen(nmp->nm_sprinc)); } - + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_NFS_PORT)) { + struct sockaddr_un *un = (struct sockaddr_un *)nmp->nm_saddr; + xb_add_string(error, &xbinfo, un->sun_path, strlen(un->sun_path)); + } + if (NFS_BITMAP_ISSET(mattrs, NFS_MATTR_LOCAL_MOUNT_PORT)) { + xb_add_string(error, &xbinfo, nmp->nm_mount_localport, strlen(nmp->nm_mount_localport)); + } curargs_end_offset = xb_offset(&xbinfo); /* NFS_MIATTR_CUR_LOC_INDEX */ @@ -5924,8 +6186,9 @@ nfs_vfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, struct xdrbuf xb; struct netfs_status *nsp = NULL; int timeoutmask; - uint pos, totlen, count, numThreads; -#if NFSSERVER + uint totlen, count, numThreads; +#if CONFIG_NFS_SERVER + uint pos; struct nfs_exportfs *nxfs; struct nfs_export *nx; struct nfs_active_user_list *ulist; @@ -5937,7 +6200,7 @@ nfs_vfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, struct nfs_user_stat_path_rec upath_rec; uint bytes_avail, bytes_total, recs_copied; uint numExports, numRecs; -#endif /* NFSSERVER */ +#endif /* CONFIG_NFS_SERVER */ /* * All names at this level are terminal. @@ -6033,7 +6296,7 @@ nfs_vfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, if (((nmp = VFSTONFS(mp))) == NULL) { return ENOENT; } - xb_init(&xb, 0); + xb_init(&xb, XDRBUF_NONE); if ((error = nfs_mountinfo_assemble(nmp, &xb))) { return error; } @@ -6045,7 +6308,7 @@ nfs_vfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, *oldlenp = xb.xb_u.xb_buffer.xbb_len; xb_cleanup(&xb); break; -#if NFSSERVER +#if CONFIG_NFS_SERVER case NFS_EXPORTSTATS: /* setup export stat descriptor */ stat_desc.rec_vers = NFS_EXPORT_STAT_REC_VERSION; @@ -6291,7 +6554,7 @@ ustat_skip: error = copyout(&nfsrv_user_stat_node_count, oldp, sizeof(nfsrv_user_stat_node_count)); break; -#endif /* NFSSERVER */ +#endif /* CONFIG_NFS_SERVER */ case VFS_CTL_NOLOCKS: if (req->oldptr != USER_ADDR_NULL) { lck_mtx_lock(&nmp->nm_lock); @@ -6311,9 +6574,11 @@ ustat_skip: if (nmp->nm_lockmode == NFS_LOCK_MODE_LOCAL) { /* can't toggle locks when using local locks */ error = EINVAL; +#if CONFIG_NFS4 } else if ((nmp->nm_vers >= NFS_VER4) && val) { /* can't disable locks for NFSv4 */ error = EINVAL; +#endif } else if (val) { if ((nmp->nm_vers <= NFS_VER3) && (nmp->nm_lockmode == NFS_LOCK_MODE_ENABLED)) { nfs_lockd_mount_unregister(nmp); @@ -6467,3 +6732,5 @@ ustat_skip: } return error; } + +#endif /* CONFIG_NFS_CLIENT */