/*
- * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/vm.h>
#include <sys/vmparam.h>
+#include <netinet/in.h>
+
#include <nfs/nfsproto.h>
#include <nfs/rpcv2.h>
#include <nfs/nfs.h>
struct nfsrv_sockhead nfsrv_socklist, nfsrv_deadsocklist, nfsrv_sockwg,
nfsrv_sockwait, nfsrv_sockwork;
struct nfsrv_sock *nfsrv_udpsock = NULL;
+struct nfsrv_sock *nfsrv_udp6sock = NULL;
/* NFS exports */
struct nfsrv_expfs_list nfsrv_exports;
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;
}
* obtain good performance in the optimistic mode.
*/
if (nfsmode & NFS_ACCESS_READ) {
- if (vnode_isdir(vp)) {
- testaction =
- KAUTH_VNODE_LIST_DIRECTORY |
- KAUTH_VNODE_READ_EXTATTRIBUTES;
- } else {
- testaction =
- KAUTH_VNODE_READ_DATA |
- KAUTH_VNODE_READ_EXTATTRIBUTES;
- }
+ 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;
}
nfsmerr_if(error);
ni.ni_cnd.cn_nameiop = LOOKUP;
+#if CONFIG_TRIGGERS
+ ni.ni_op = OP_LOOKUP;
+#endif
ni.ni_cnd.cn_flags = LOCKLEAF;
error = nfsm_chain_get_path_namei(nmreq, len, &ni);
isdotdot = ((len == 2) && (ni.ni_cnd.cn_pnbuf[0] == '.') && (ni.ni_cnd.cn_pnbuf[1] == '.'));
* entry and free it.
*/
LIST_FOREACH_SAFE(fp, &firehead, fm_link, nfp) {
- if (nfsrv_fsevents_enabled)
+ if (nfsrv_fsevents_enabled) {
+ fp->fm_context.vc_thread = current_thread();
add_fsevent(FSE_CONTENT_MODIFIED, &fp->fm_context,
FSE_ARG_VNODE, fp->fm_vp,
FSE_ARG_DONE);
+ }
vnode_put(fp->fm_vp);
kauth_cred_unref(&fp->fm_context.vc_ucred);
LIST_REMOVE(fp, fm_link);
ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
error = VNOP_WRITE(vp, auio, ioflags, ctx);
- OSAddAtomic(1, &nfsstats.srvvop_writes);
+ OSAddAtomic64(1, &nfsstats.srvvop_writes);
/* update export stats */
NFSStatAdd64(&nx->nx_stats.bytes_written, len);
if ((tlen = mbuf_len(m)) > 0)
uio_addiov(auio, CAST_USER_ADDR_T((caddr_t)mbuf_data(m)), tlen);
error = VNOP_WRITE(vp, auio, ioflags, ctx);
- OSAddAtomic(1, &nfsstats.srvvop_writes);
+ OSAddAtomic64(1, &nfsstats.srvvop_writes);
/* update export stats */
NFSStatAdd64(&nx->nx_stats.bytes_written, nd->nd_len);
ni.ni_cnd.cn_nameiop = 0;
rdev = 0;
- /*
- * Save the original credential UID in case they are
- * mapped and we need to map the IDs in the attributes.
- */
saved_uid = kauth_cred_getuid(nd->nd_cr);
nfsm_chain_get_fh_ptr(error, nmreq, nd->nd_vers, nfh.nfh_fhp, nfh.nfh_len);
nfsmerr_if(error);
ni.ni_cnd.cn_nameiop = CREATE;
+#if CONFIG_TRIGGERS
+ ni.ni_op = OP_LINK;
+#endif
ni.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
error = nfsm_chain_get_path_namei(nmreq, len, &ni);
if (!error) {
if (vp == NULL) {
kauth_acl_t xacl = NULL;
- /*
- * If the credentials were mapped, we should
- * map the same values in the attributes.
- */
- if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nd->nd_cr) != saved_uid)) {
- int ismember;
- VATTR_SET(vap, va_uid, kauth_cred_getuid(nd->nd_cr));
- if (kauth_cred_ismember_gid(nd->nd_cr, vap->va_gid, &ismember) || !ismember)
- VATTR_SET(vap, va_gid, kauth_cred_getgid(nd->nd_cr));
- }
-
/* authorize before creating */
error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx, nxo, 0);
}
VATTR_CLEAR_ACTIVE(vap, va_data_size);
VATTR_CLEAR_ACTIVE(vap, va_access_time);
+ /*
+ * Server policy is to alway use the mapped rpc credential for
+ * file system object creation. This has the nice side effect of
+ * enforcing BSD creation semantics
+ */
+ VATTR_CLEAR_ACTIVE(vap, va_uid);
+ VATTR_CLEAR_ACTIVE(vap, va_gid);
/* validate new-file security information */
- if (!error) {
+ if (!error)
error = vnode_authattr_new(dvp, vap, 0, ctx);
- if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
- /*
- * Most NFS servers just ignore the UID/GID attributes, so we
- * try ignoring them if that'll help the request succeed.
- */
- VATTR_CLEAR_ACTIVE(vap, va_uid);
- VATTR_CLEAR_ACTIVE(vap, va_gid);
- error = vnode_authattr_new(dvp, vap, 0, ctx);
- }
- }
if (vap->va_type == VREG || vap->va_type == VSOCK) {
vp = NULL;
}
ni.ni_cnd.cn_nameiop = LOOKUP;
+#if CONFIG_TRIGGERS
+ ni.ni_op = OP_LOOKUP;
+#endif
ni.ni_cnd.cn_flags &= ~LOCKPARENT;
ni.ni_cnd.cn_context = ctx;
ni.ni_startdir = dvp;
uint32_t len = 0, cnflags;
u_int32_t major = 0, minor = 0;
enum vtype vtyp;
+ nfstype nvtype;
vnode_t vp, dvp, dirp;
struct nfs_filehandle nfh;
struct nfs_export *nx = NULL;
vp = dvp = dirp = NULL;
ni.ni_cnd.cn_nameiop = 0;
- /*
- * Save the original credential UID in case they are
- * mapped and we need to map the IDs in the attributes.
- */
saved_uid = kauth_cred_getuid(nd->nd_cr);
nfsm_chain_get_fh_ptr(error, nmreq, NFS_VER3, nfh.nfh_fhp, nfh.nfh_len);
nfsmerr_if(error);
ni.ni_cnd.cn_nameiop = CREATE;
+#if CONFIG_TRIGGERS
+ ni.ni_op = OP_LINK;
+#endif
ni.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
error = nfsm_chain_get_path_namei(nmreq, len, &ni);
if (!error) {
dvp = ni.ni_dvp;
vp = ni.ni_vp;
- nfsm_chain_get_32(error, nmreq, vtyp);
+ nfsm_chain_get_32(error, nmreq, nvtype);
nfsmerr_if(error);
- vtyp = nfstov_type(vtyp, NFS_VER3);
+ vtyp = nfstov_type(nvtype, NFS_VER3);
if (!error && (vtyp != VCHR) && (vtyp != VBLK) && (vtyp != VSOCK) && (vtyp != VFIFO)) {
error = NFSERR_BADTYPE;
goto out;
}
VATTR_SET(vap, va_type, vtyp);
- /*
- * If the credentials were mapped, we should
- * map the same values in the attributes.
- */
- if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nd->nd_cr) != saved_uid)) {
- int ismember;
- VATTR_SET(vap, va_uid, kauth_cred_getuid(nd->nd_cr));
- if (kauth_cred_ismember_gid(nd->nd_cr, vap->va_gid, &ismember) || !ismember)
- VATTR_SET(vap, va_gid, kauth_cred_getgid(nd->nd_cr));
- }
-
/* authorize before creating */
error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx, nxo, 0);
}
VATTR_CLEAR_ACTIVE(vap, va_data_size);
VATTR_CLEAR_ACTIVE(vap, va_access_time);
+ /*
+ * Server policy is to alway use the mapped rpc credential for
+ * file system object creation. This has the nice side effect of
+ * enforcing BSD creation semantics
+ */
+ VATTR_CLEAR_ACTIVE(vap, va_uid);
+ VATTR_CLEAR_ACTIVE(vap, va_gid);
/* validate new-file security information */
- if (!error) {
+ if (!error)
error = vnode_authattr_new(dvp, vap, 0, ctx);
- if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
- /*
- * Most NFS servers just ignore the UID/GID attributes, so we
- * try ignoring them if that'll help the request succeed.
- */
- VATTR_CLEAR_ACTIVE(vap, va_uid);
- VATTR_CLEAR_ACTIVE(vap, va_gid);
- error = vnode_authattr_new(dvp, vap, 0, ctx);
- }
- }
+
if (error)
goto out1;
vp = NULL;
}
ni.ni_cnd.cn_nameiop = LOOKUP;
+#if CONFIG_TRIGGERS
+ ni.ni_op = OP_LOOKUP;
+#endif
ni.ni_cnd.cn_flags &= ~LOCKPARENT;
ni.ni_cnd.cn_context = vfs_context_current();
ni.ni_startdir = dvp;
nfsmerr_if(error);
ni.ni_cnd.cn_nameiop = DELETE;
+#if CONFIG_TRIGGERS
+ ni.ni_op = OP_UNLINK;
+#endif
ni.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
error = nfsm_chain_get_path_namei(nmreq, len, &ni);
if (!error) {
kauth_cred_ref(saved_cred);
retry:
fromni.ni_cnd.cn_nameiop = DELETE;
+#if CONFIG_TRIGGERS
+ fromni.ni_op = OP_UNLINK;
+#endif
fromni.ni_cnd.cn_flags = WANTPARENT;
fromni.ni_cnd.cn_pnbuf = frompath;
}
toni.ni_cnd.cn_nameiop = RENAME;
+#if CONFIG_TRIGGERS
+ toni.ni_op = OP_RENAME;
+#endif
toni.ni_cnd.cn_flags = WANTPARENT;
toni.ni_cnd.cn_pnbuf = topath;
goto out;
ni.ni_cnd.cn_nameiop = CREATE;
+#if CONFIG_TRIGGERS
+ ni.ni_op = OP_LINK;
+#endif
ni.ni_cnd.cn_flags = LOCKPARENT;
error = nfsm_chain_get_path_namei(nmreq, len, &ni);
if (!error)
linkdata = NULL;
dirp = NULL;
- /*
- * Save the original credential UID in case they are
- * mapped and we need to map the IDs in the attributes.
- */
saved_uid = kauth_cred_getuid(nd->nd_cr);
ni.ni_cnd.cn_nameiop = 0;
nfsmerr_if(error);
ni.ni_cnd.cn_nameiop = CREATE;
+#if CONFIG_TRIGGERS
+ ni.ni_op = OP_LINK;
+#endif
ni.ni_cnd.cn_flags = LOCKPARENT;
error = nfsm_chain_get_path_namei(nmreq, len, &ni);
if (!error) {
goto out;
}
- /*
- * If the credentials were mapped, we should
- * map the same values in the attributes.
- */
- if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nd->nd_cr) != saved_uid)) {
- int ismember;
- VATTR_SET(vap, va_uid, kauth_cred_getuid(nd->nd_cr));
- if (kauth_cred_ismember_gid(nd->nd_cr, vap->va_gid, &ismember) || !ismember)
- VATTR_SET(vap, va_gid, kauth_cred_getgid(nd->nd_cr));
- }
VATTR_SET(vap, va_type, VLNK);
VATTR_CLEAR_ACTIVE(vap, va_data_size);
VATTR_CLEAR_ACTIVE(vap, va_access_time);
+ /*
+ * Server policy is to alway use the mapped rpc credential for
+ * file system object creation. This has the nice side effect of
+ * enforcing BSD creation semantics
+ */
+ VATTR_CLEAR_ACTIVE(vap, va_uid);
+ VATTR_CLEAR_ACTIVE(vap, va_gid);
/* authorize before creating */
error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx, nxo, 0);
/* validate given attributes */
- if (!error) {
+ if (!error)
error = vnode_authattr_new(dvp, vap, 0, ctx);
- if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
- /*
- * Most NFS servers just ignore the UID/GID attributes, so we
- * try ignoring them if that'll help the request succeed.
- */
- VATTR_CLEAR_ACTIVE(vap, va_uid);
- VATTR_CLEAR_ACTIVE(vap, va_gid);
- error = vnode_authattr_new(dvp, vap, 0, ctx);
- }
- }
+
if (!error)
error = VNOP_SYMLINK(dvp, &vp, &ni.ni_cnd, vap, linkdata, ctx);
if (!error && (nd->nd_vers == NFS_VER3)) {
if (vp == NULL) {
ni.ni_cnd.cn_nameiop = LOOKUP;
+#if CONFIG_TRIGGERS
+ ni.ni_op = OP_LOOKUP;
+#endif
ni.ni_cnd.cn_flags &= ~(LOCKPARENT | FOLLOW);
ni.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
ni.ni_cnd.cn_context = ctx;
/*
* nfs mkdir service
*/
+
int
nfsrv_mkdir(
struct nfsrv_descript *nd,
nmreq = &nd->nd_nmreq;
nfsm_chain_null(&nmrep);
- /*
- * Save the original credential UID in case they are
- * mapped and we need to map the IDs in the attributes.
- */
saved_uid = kauth_cred_getuid(nd->nd_cr);
ni.ni_cnd.cn_nameiop = 0;
nfsmerr_if(error);
ni.ni_cnd.cn_nameiop = CREATE;
+#if CONFIG_TRIGGERS
+ ni.ni_op = OP_LINK;
+#endif
ni.ni_cnd.cn_flags = LOCKPARENT;
error = nfsm_chain_get_path_namei(nmreq, len, &ni);
if (!error) {
goto out;
}
- /*
- * If the credentials were mapped, we should
- * map the same values in the attributes.
- */
- if ((vap->va_uid == saved_uid) && (kauth_cred_getuid(nd->nd_cr) != saved_uid)) {
- int ismember;
- VATTR_SET(vap, va_uid, kauth_cred_getuid(nd->nd_cr));
- if (kauth_cred_ismember_gid(nd->nd_cr, vap->va_gid, &ismember) || !ismember)
- VATTR_SET(vap, va_gid, kauth_cred_getgid(nd->nd_cr));
- }
-
error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_SUBDIRECTORY, ctx, nxo, 0);
/* construct ACL and handle inheritance */
if (!error && xacl != NULL)
VATTR_SET(vap, va_acl, xacl);
}
+
VATTR_CLEAR_ACTIVE(vap, va_data_size);
VATTR_CLEAR_ACTIVE(vap, va_access_time);
+ /*
+ * We don't support the S_ISGID bit for directories. Solaris and other
+ * SRV4 derived systems might set this to get BSD semantics, which we enforce
+ * any ways.
+ */
+ if (VATTR_IS_ACTIVE(vap, va_mode))
+ vap->va_mode &= ~S_ISGID;
+ /*
+ * Server policy is to alway use the mapped rpc credential for
+ * file system object creation. This has the nice side effect of
+ * enforcing BSD creation semantics
+ */
+ VATTR_CLEAR_ACTIVE(vap, va_uid);
+ VATTR_CLEAR_ACTIVE(vap, va_gid);
/* validate new-file security information */
- if (!error) {
+ if (!error)
error = vnode_authattr_new(dvp, vap, 0, ctx);
- if (error && (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid))) {
- /*
- * Most NFS servers just ignore the UID/GID attributes, so we
- * try ignoring them if that'll help the request succeed.
- */
- VATTR_CLEAR_ACTIVE(vap, va_uid);
- VATTR_CLEAR_ACTIVE(vap, va_gid);
- error = vnode_authattr_new(dvp, vap, 0, ctx);
- }
- }
+ /*
+ * vnode_authattr_new can return errors other than EPERM, but that's not going to
+ * sit well with our clients so we map all errors to EPERM.
+ */
+ if (error)
+ error = EPERM;
if (!error)
error = VNOP_MKDIR(dvp, &vp, &ni.ni_cnd, vap, ctx);
nfsmerr_if(error);
ni.ni_cnd.cn_nameiop = DELETE;
+#if CONFIG_TRIGGERS
+ ni.ni_op = OP_UNLINK;
+#endif
ni.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
error = nfsm_chain_get_path_namei(nmreq, len, &ni);
if (!error) {
error = nfsrv_credcheck(nd, ctx, nx, nxo);
nfsmerr_if(error);
+ if (nxo->nxo_flags & NX_MANGLEDNAMES || nd->nd_vers == NFS_VER2)
+ vnopflag |= VNODE_READDIR_NAMEMAX;
+
if ((nd->nd_vers == NFS_VER2) || (nxo->nxo_flags & NX_32BITCLIENTS))
vnopflag |= VNODE_READDIR_SEEKOFF32;
+
if (nd->nd_vers == NFS_VER3) {
nfsm_srv_vattr_init(&attr, NFS_VER3);
error = attrerr = vnode_getattr(vp, &attr, ctx);
if (nxo->nxo_flags & NX_32BITCLIENTS)
vnopflag |= VNODE_READDIR_SEEKOFF32;
+ if (nxo->nxo_flags & NX_MANGLEDNAMES)
+ vnopflag |= VNODE_READDIR_NAMEMAX;
+
nfsm_srv_vattr_init(&attr, NFS_VER3);
error = attrerr = vnode_getattr(vp, &attr, ctx);
if (!error && toff && verf && (verf != attr.va_filerev))