+
+ /* initialize NFS server timer callouts */
+#if CONFIG_FSE
+ nfsrv_fmod_timer_call = thread_call_allocate(nfsrv_fmod_timer, NULL);
+#endif
+ nfsrv_deadsock_timer_call = thread_call_allocate(nfsrv_deadsock_timer, NULL);
+ nfsrv_wg_timer_call = thread_call_allocate(nfsrv_wg_timer, NULL);
+
+ /* Init server data structures */
+ TAILQ_INIT(&nfsrv_socklist);
+ TAILQ_INIT(&nfsrv_sockwait);
+ TAILQ_INIT(&nfsrv_sockwork);
+ TAILQ_INIT(&nfsrv_deadsocklist);
+ TAILQ_INIT(&nfsrv_sockwg);
+ TAILQ_INIT(&nfsd_head);
+ TAILQ_INIT(&nfsd_queue);
+ nfsrv_udpsock = NULL;
+ nfsrv_udp6sock = NULL;
+
+ /* Setup the up-call handling */
+ nfsrv_uc_init();
+
+ /* initialization complete */
+ nfsrv_initted = NFSRV_INITIALIZED;
+}
+
+
+/*
+ *
+ * NFS version 2 and 3 server request processing functions
+ *
+ * These functions take the following parameters:
+ *
+ * struct nfsrv_descript *nd - the NFS request descriptor
+ * struct nfsrv_sock *slp - the NFS socket the request came in on
+ * vfs_context_t ctx - VFS context
+ * mbuf_t *mrepp - pointer to hold the reply mbuf list
+ *
+ * These routines generally have 3 phases:
+ *
+ * 1 - break down and validate the RPC request in the mbuf chain
+ * provided in nd->nd_nmreq.
+ * 2 - perform the vnode operations for the request
+ * (many are very similar to syscalls in vfs_syscalls.c and
+ * should therefore be kept in sync with those implementations)
+ * 3 - build the RPC reply in an mbuf chain (nmrep) and return the mbuf chain
+ *
+ */
+
+/*
+ * nfs v3 access service
+ */
+int
+nfsrv_access(
+ struct nfsrv_descript *nd,
+ struct nfsrv_sock *slp,
+ vfs_context_t ctx,
+ mbuf_t *mrepp)
+{
+ struct nfsm_chain *nmreq, nmrep;
+ vnode_t vp;
+ int error, attrerr;
+ struct vnode_attr vattr;
+ struct nfs_filehandle nfh;
+ u_int32_t nfsmode;
+ kauth_action_t testaction;
+ struct nfs_export *nx;
+ struct nfs_export_options *nxo;
+
+ error = 0;
+ attrerr = ENOENT;
+ nfsmode = 0;
+ nmreq = &nd->nd_nmreq;
+ nfsm_chain_null(&nmrep);
+ *mrepp = NULL;
+ vp = NULL;
+
+ nfsm_chain_get_fh_ptr(error, nmreq, NFS_VER3, nfh.nfh_fhp, nfh.nfh_len);
+ nfsm_chain_get_32(error, nmreq, nfsmode);
+ nfsmerr_if(error);
+ error = nfsrv_fhtovp(&nfh, nd, &vp, &nx, &nxo);
+ nfsmerr_if(error);
+
+ /* update export stats */
+ NFSStatAdd64(&nx->nx_stats.ops, 1);
+
+ /* update active user stats */
+ nfsrv_update_user_stat(nx, nd, kauth_cred_getuid(nd->nd_cr), 1, 0, 0);
+
+ error = nfsrv_credcheck(nd, ctx, nx, nxo);
+ nfsmerr_if(error);
+
+ /*
+ * Each NFS mode bit is tested separately.
+ *
+ * XXX this code is nominally correct, but returns a pessimistic
+ * rather than optimistic result. It will be necessary to add
+ * an NFS-specific interface to the vnode_authorize code to
+ * obtain good performance in the optimistic mode.
+ */
+ if (nfsmode & NFS_ACCESS_READ) {
+ testaction = vnode_isdir(vp) ? KAUTH_VNODE_LIST_DIRECTORY : KAUTH_VNODE_READ_DATA;
+ if (nfsrv_authorize(vp, NULL, testaction, ctx, nxo, 0))
+ nfsmode &= ~NFS_ACCESS_READ;
+ }
+ if ((nfsmode & NFS_ACCESS_LOOKUP) &&
+ (!vnode_isdir(vp) ||
+ nfsrv_authorize(vp, NULL, KAUTH_VNODE_SEARCH, ctx, nxo, 0)))
+ nfsmode &= ~NFS_ACCESS_LOOKUP;
+ if (nfsmode & NFS_ACCESS_MODIFY) {
+ if (vnode_isdir(vp)) {
+ testaction =
+ KAUTH_VNODE_ADD_FILE |
+ KAUTH_VNODE_ADD_SUBDIRECTORY |
+ KAUTH_VNODE_DELETE_CHILD;
+ } else {
+ testaction =
+ KAUTH_VNODE_WRITE_DATA;
+ }
+ if (nfsrv_authorize(vp, NULL, testaction, ctx, nxo, 0))
+ nfsmode &= ~NFS_ACCESS_MODIFY;
+ }
+ if (nfsmode & NFS_ACCESS_EXTEND) {
+ if (vnode_isdir(vp)) {
+ testaction =
+ KAUTH_VNODE_ADD_FILE |
+ KAUTH_VNODE_ADD_SUBDIRECTORY;
+ } else {
+ testaction =
+ KAUTH_VNODE_WRITE_DATA |
+ KAUTH_VNODE_APPEND_DATA;
+ }
+ if (nfsrv_authorize(vp, NULL, testaction, ctx, nxo, 0))
+ nfsmode &= ~NFS_ACCESS_EXTEND;