]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/nfs/nfs_serv.c
xnu-3789.41.3.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_serv.c
index 8cc717b8eb779834c179490a43921d957447c5f6..7431b656234ec9e60e49bd7c9dd0ace20d607038 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2011 Apple Inc.  All rights reserved.
+ * Copyright (c) 2000-2014 Apple Inc.  All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
 #include <libkern/OSAtomic.h>
 #include <sys/fsevents.h>
 #include <kern/thread_call.h>
+#include <sys/time.h>
 
 #include <sys/vm.h>
 #include <sys/vmparam.h>
 
+#include <sys/fcntl.h>
+
 #include <netinet/in.h>
 
 #include <nfs/nfsproto.h>
 #include <nfs/nfsrvcache.h>
 #include <nfs/nfs_gss.h>
 
+#if CONFIG_MACF
+#include <security/mac.h>
+#include <security/mac_framework.h>
+#endif
+
 #if NFSSERVER
 
 /*
@@ -113,7 +121,7 @@ struct nfsd_head nfsd_head, nfsd_queue;
 
 lck_grp_t *nfsrv_slp_rwlock_group;
 lck_grp_t *nfsrv_slp_mutex_group;
-struct nfsrv_sockhead nfsrv_socklist, nfsrv_deadsocklist, nfsrv_sockwg,
+struct nfsrv_sockhead nfsrv_socklist, nfsrv_sockwg,
                        nfsrv_sockwait, nfsrv_sockwork;
 struct nfsrv_sock *nfsrv_udpsock = NULL;
 struct nfsrv_sock *nfsrv_udp6sock = NULL;
@@ -140,7 +148,7 @@ int nfsrv_fsevents_enabled = 1;
 #if CONFIG_FSE
 thread_call_t  nfsrv_fmod_timer_call;
 #endif
-thread_call_t  nfsrv_deadsock_timer_call;
+thread_call_t  nfsrv_idlesock_timer_call;
 thread_call_t  nfsrv_wg_timer_call;
 int nfsrv_wg_timer_on;
 
@@ -223,14 +231,13 @@ nfsrv_init(void)
 #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_idlesock_timer_call = thread_call_allocate(nfsrv_idlesock_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);
@@ -548,6 +555,34 @@ nfsrv_setattr(
        if (!error)
                error = nfsrv_authorize(vp, NULL, action, ctx, nxo, 0);
 
+#if CONFIG_MACF
+       if (!error) {
+               /* chown case */
+               if (VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid)) {
+                       error = mac_vnode_check_setowner(ctx, vp,
+                               VATTR_IS_ACTIVE(vap, va_uid) ? vap->va_uid : -1,
+                               VATTR_IS_ACTIVE(vap, va_gid) ? vap->va_gid : -1);
+               }
+               /* chmod case */
+               if (!error && VATTR_IS_ACTIVE(vap, va_mode)) {
+                       error = mac_vnode_check_setmode(ctx, vp, (mode_t)vap->va_mode);
+               }
+               /* truncate case */
+               if (!error && VATTR_IS_ACTIVE(vap, va_data_size)) {
+                       /* NOTE: File has not been open for NFS case, so NOCRED for filecred */
+                       error = mac_vnode_check_truncate(ctx, NOCRED, vp);
+               }
+               /* set utimes case */
+               if (!error && (VATTR_IS_ACTIVE(vap, va_access_time) || VATTR_IS_ACTIVE(vap, va_modify_time))) {
+                       struct timespec current_time;
+                       nanotime(&current_time);
+
+                       error = mac_vnode_check_setutimes(ctx, vp,
+                                                         VATTR_IS_ACTIVE(vap, va_access_time) ? vap->va_access_time : current_time,
+                                                         VATTR_IS_ACTIVE(vap, va_modify_time) ? vap->va_modify_time : current_time);
+               }
+       }
+#endif
        /* set the new attributes */
        if (!error)
                error = vnode_setattr(vp, vap, ctx);
@@ -1257,6 +1292,21 @@ nfsrv_write(
                error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_WRITE_DATA, ctx, nxo, 1);
        nfsmerr_if(error);
 
+#if CONFIG_MACF
+       if (!error) {
+               error = mac_vnode_check_open(ctx, vp, FWRITE);
+               if (error) {
+                       error = EACCES;
+               } else {
+                       /* XXXab: Do we need to do this?! */
+                       error = mac_vnode_check_write(ctx, vfs_context_ucred(ctx), vp);
+                       if (error)
+                               error = EACCES;
+               }
+       }
+       nfsmerr_if(error);
+#endif
+
        if (len > 0) {
                for (mcount=0, m=nmreq->nmc_mcur; m; m = mbuf_next(m))
                        if (mbuf_len(m) > 0)
@@ -1845,6 +1895,8 @@ nfsrv_create(
        ni.ni_op = OP_LINK;
 #endif
        ni.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
+       ni.ni_cnd.cn_ndp = &ni;
+
        error = nfsm_chain_get_path_namei(nmreq, len, &ni);
        if (!error) {
                error = nfsrv_namei(nd, ctx, &ni, &nfh, &dirp, &nx, &nxo);
@@ -1954,6 +2006,12 @@ nfsrv_create(
                if (!error) 
                        error = vnode_authattr_new(dvp, vap, 0, ctx);
 
+               if (!error) {
+                       error = vn_authorize_create(dvp, &ni.ni_cnd, vap, ctx, NULL);
+                       if (error)
+                               error = EACCES;
+               }
+
                if (vap->va_type == VREG || vap->va_type == VSOCK) {
 
                        if (!error)
@@ -2053,6 +2111,14 @@ nfsrv_create(
 
                vnode_put(dvp);
 
+#if CONFIG_MACF
+               if (!error && VATTR_IS_ACTIVE(vap, va_data_size)) {
+                       /* NOTE: File has not been open for NFS case, so NOCRED for filecred */
+                       error = mac_vnode_check_truncate(ctx, NOCRED, vp);
+                       if (error)
+                               error = EACCES;
+               }
+#endif
                if (!error && VATTR_IS_ACTIVE(vap, va_data_size)) {
                        error = nfsrv_authorize(vp, NULL, KAUTH_VNODE_WRITE_DATA,
                            ctx, nxo, 0);
@@ -2173,6 +2239,7 @@ nfsrv_mknod(
        ni.ni_op = OP_LINK;
 #endif
        ni.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
+       ni.ni_cnd.cn_ndp = &ni;
        error = nfsm_chain_get_path_namei(nmreq, len, &ni);
        if (!error) {
                error = nfsrv_namei(nd, ctx, &ni, &nfh, &dirp, &nx, &nxo);
@@ -2250,7 +2317,11 @@ nfsrv_mknod(
        /* validate new-file security information */
        if (!error) 
                error = vnode_authattr_new(dvp, vap, 0, ctx);
-
+       if (!error) {
+               error = vn_authorize_create(dvp, &ni.ni_cnd, vap, ctx, NULL);
+               if (error)
+                       error = EACCES;
+       }
        if (error)
                goto out1;
 
@@ -2402,6 +2473,7 @@ nfsrv_remove(
        ni.ni_op = OP_UNLINK;
 #endif
        ni.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
+       ni.ni_cnd.cn_ndp = &ni;
        error = nfsm_chain_get_path_namei(nmreq, len, &ni);
        if (!error) {
                error = nfsrv_namei(nd, ctx, &ni, &nfh, &dirp, &nx, &nxo);
@@ -2437,6 +2509,12 @@ nfsrv_remove(
                else
                        error = nfsrv_authorize(vp, dvp, KAUTH_VNODE_DELETE, ctx, nxo, 0);
 
+               if (!error) {
+                       error = vn_authorize_unlink(dvp, vp, &ni.ni_cnd, ctx, NULL);
+                       if (error)
+                               error = EACCES;
+               }
+
                if (!error) {
 #if CONFIG_FSE
                        char     *path = NULL;
@@ -2590,6 +2668,7 @@ retry:
        frompath = NULL;
        fromni.ni_cnd.cn_pnlen = MAXPATHLEN;
        fromni.ni_cnd.cn_flags |= HASBUF;
+       fromni.ni_cnd.cn_ndp = &fromni;
 
        error = nfsrv_namei(nd, ctx, &fromni, &fnfh, &fdirp, &fnx, &fnxo);
        if (error)
@@ -2625,6 +2704,7 @@ retry:
        topath = NULL;
        toni.ni_cnd.cn_pnlen = MAXPATHLEN;
        toni.ni_cnd.cn_flags |= HASBUF;
+       toni.ni_cnd.cn_ndp = &toni;
 
        if (fvtype == VDIR)
                toni.ni_cnd.cn_flags |= WILLBEDIR;
@@ -2744,6 +2824,12 @@ retry:
                    ((error = nfsrv_authorize(tvp, tdvp, KAUTH_VNODE_DELETE, ctx, tnxo, 0)) != 0))
                        goto auth_exit;
 
+               if (!error &&
+                   ((error = vn_authorize_rename(fdvp, fvp, &fromni.ni_cnd , tdvp, tvp, &toni.ni_cnd , ctx, NULL)) != 0)) {
+                       if (error)
+                               error = EACCES;
+                       goto auth_exit;
+               }
                /* XXX more checks? */
 
 auth_exit:
@@ -3194,6 +3280,13 @@ nfsrv_link(
        else
                error = nfsrv_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx, nxo, 0);
 
+#if CONFIG_MACF
+       if (!error) {
+               error = mac_vnode_check_link(ctx, dvp, vp, &ni.ni_cnd);
+               if (error)
+                       error = EACCES;
+       }
+#endif
        if (!error)
                error = VNOP_LINK(vp, dvp, &ni.ni_cnd, ctx);
 
@@ -3316,6 +3409,8 @@ nfsrv_symlink(
        ni.ni_op = OP_LINK;
 #endif
        ni.ni_cnd.cn_flags = LOCKPARENT;
+       ni.ni_flag = 0;
+       ni.ni_cnd.cn_ndp = &ni;
        error = nfsm_chain_get_path_namei(nmreq, len, &ni);
        if (!error) {
                error = nfsrv_namei(nd, ctx, &ni, &nfh, &dirp, &nx, &nxo);
@@ -3387,6 +3482,11 @@ nfsrv_symlink(
        /* validate given attributes */
        if (!error)
                error = vnode_authattr_new(dvp, vap, 0, ctx);
+       if (!error) {
+               error = vn_authorize_create(dvp, &ni.ni_cnd, vap, ctx, NULL);
+               if (error)
+                       error = EACCES;
+       }
 
        if (!error)
                error = VNOP_SYMLINK(dvp, &vp, &ni.ni_cnd, vap, linkdata, ctx);
@@ -3532,7 +3632,8 @@ nfsrv_mkdir(
 #if CONFIG_TRIGGERS
        ni.ni_op = OP_LINK;
 #endif
-       ni.ni_cnd.cn_flags = LOCKPARENT;
+       ni.ni_cnd.cn_flags = LOCKPARENT | WILLBEDIR;
+       ni.ni_cnd.cn_ndp = &ni;
        error = nfsm_chain_get_path_namei(nmreq, len, &ni);
        if (!error) {
                error = nfsrv_namei(nd, ctx, &ni, &nfh, &dirp, &nx, &nxo);
@@ -3618,6 +3719,12 @@ nfsrv_mkdir(
        if (error)
                error = EPERM;
 
+       if(!error) {
+               error = vn_authorize_mkdir(dvp, &ni.ni_cnd, vap, ctx, NULL);
+               if (error)
+                       error = EACCES;
+       }
+
        if (!error)
                error = VNOP_MKDIR(dvp, &vp, &ni.ni_cnd, vap, ctx);
 
@@ -3743,6 +3850,7 @@ nfsrv_rmdir(
        ni.ni_op = OP_UNLINK;
 #endif
        ni.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
+       ni.ni_cnd.cn_ndp = &ni;
        error = nfsm_chain_get_path_namei(nmreq, len, &ni);
        if (!error) {
                error = nfsrv_namei(nd, ctx, &ni, &nfh, &dirp, &nx, &nxo);
@@ -3786,6 +3894,12 @@ nfsrv_rmdir(
                error = EBUSY;
        if (!error)
                error = nfsrv_authorize(vp, dvp, KAUTH_VNODE_DELETE, ctx, nxo, 0);
+       if (!error) {
+               error = vn_authorize_rmdir(dvp, vp, &ni.ni_cnd, ctx, NULL);
+               if (error)
+                       error = EACCES;
+       }
+
        if (!error) {
 #if CONFIG_FSE
                char     *path = NULL;