Windows: Freelance HaveAccessRights
[openafs.git] / src / WINNT / afsd / cm_access.c
index 5b9d6bd..79692b1 100644 (file)
@@ -1,18 +1,20 @@
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+#include <afsconfig.h>
 #include <afs/param.h>
+#include <roken.h>
+
 #include <afs/stds.h>
 
 #include <windows.h>
 #include <winsock2.h>
-#include <malloc.h>
 #include <string.h>
 #include <stdlib.h>
 #include <nb30.h>
@@ -21,6 +23,7 @@
 #include "afsd.h"
 
 int cm_deleteReadOnly = 0;
+int cm_accessPerFileCheck = 0;
 
 /* called with scp write-locked, check to see if we have the ACL info we need
  * and can get it w/o blocking for any locks.
@@ -30,7 +33,8 @@ int cm_deleteReadOnly = 0;
  * can't be locked.  Thus, this must always be called in a while loop to stabilize
  * things, since we can always lose the race condition getting to the parent vnode.
  */
-int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *userp, afs_uint32 rights,
+int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *userp, cm_req_t *reqp,
+                        afs_uint32 rights,
                         afs_uint32 *outRightsp)
 {
     cm_scache_t *aclScp;
@@ -38,44 +42,49 @@ int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *userp, afs_uint32
     cm_fid_t tfid;
     int didLock;
     long trights;
-       
+    int release = 0;    /* Used to avoid a call to cm_HoldSCache in the directory case */
+
     didLock = 0;
-    if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
-        aclScp = scp;
-        cm_HoldSCache(scp);
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY || cm_accessPerFileCheck) {
+        aclScp = scp;   /* not held, not released */
     } else {
-        tfid.cell = scp->fid.cell;
-        tfid.volume = scp->fid.volume;
-        tfid.vnode = scp->parentVnode;
-        tfid.unique = scp->parentUnique;
+        cm_SetFid(&tfid, scp->fid.cell, scp->fid.volume, scp->parentVnode, scp->parentUnique);
         aclScp = cm_FindSCache(&tfid);
-        if (!aclScp) 
+        if (!aclScp)
             return 0;
         if (aclScp != scp) {
-            code = lock_TryMutex(&aclScp->mx);
-            if (code == 0) {
-                /* can't get lock safely and easily */
-                cm_ReleaseSCache(aclScp);
-                return 0;
-            }
+            if (aclScp->fid.vnode < scp->fid.vnode)
+                lock_ReleaseWrite(&scp->rw);
+            lock_ObtainRead(&aclScp->rw);
+            if (aclScp->fid.vnode < scp->fid.vnode)
+                lock_ObtainWrite(&scp->rw);
 
-            /* check that we have a callback, too */
+           /* check that we have a callback, too */
             if (!cm_HaveCallback(aclScp)) {
                 /* can't use it */
-                lock_ReleaseMutex(&aclScp->mx);
+                lock_ReleaseRead(&aclScp->rw);
                 cm_ReleaseSCache(aclScp);
                 return 0;
             }
             didLock = 1;
         }
+        release = 1;
     }
 
-    lock_AssertMutex(&aclScp->mx);
-        
+    lock_AssertAny(&aclScp->rw);
+
     /* now if rights is a subset of the public rights, we're done.
      * Otherwise, if we an explicit acl entry, we're also in good shape,
      * and can definitively answer.
      */
+#ifdef AFS_FREELANCE_CLIENT
+    if (cm_freelanceEnabled &&
+        aclScp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+        aclScp->fid.volume==AFS_FAKE_ROOT_VOL_ID)
+    {
+       *outRightsp = aclScp->anyAccess;
+    } else
+#endif
     if ((~aclScp->anyAccess & rights) == 0) {
         *outRightsp = rights;
     } else {
@@ -88,13 +97,33 @@ int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *userp, afs_uint32
         *outRightsp = trights;
     }
 
-    /* check mode bits */
-    if (!(scp->unixModeBits & 0400))
-        *outRightsp &= ~PRSFS_READ;
-    if (!(scp->unixModeBits & 0200) && !(rights == (PRSFS_WRITE | PRSFS_LOCK)))
-        *outRightsp &= ~PRSFS_WRITE;
-    if (!(scp->unixModeBits & 0200) && !cm_deleteReadOnly)
-        *outRightsp &= ~PRSFS_DELETE;
+    if (scp->fileType > 0 && scp->fileType != CM_SCACHETYPE_DIRECTORY) {
+       /* check mode bits */
+       if ((scp->unixModeBits & 0400) == 0) {
+           osi_Log2(afsd_logp,"cm_HaveAccessRights UnixMode removing READ scp 0x%p unix 0%o",
+                     scp, scp->unixModeBits);
+           *outRightsp &= ~PRSFS_READ;
+       }
+       if ((scp->unixModeBits & 0200) == 0 && (rights != (PRSFS_WRITE | PRSFS_LOCK))) {
+           osi_Log2(afsd_logp,"cm_HaveAccessRights UnixMode removing WRITE scp 0x%p unix 0%o",
+                     scp, scp->unixModeBits);
+           *outRightsp &= ~PRSFS_WRITE;
+       }
+       if ((scp->unixModeBits & 0200) == 0 && !cm_deleteReadOnly && (reqp->flags & CM_REQ_SOURCE_SMB)) {
+           osi_Log2(afsd_logp,"cm_HaveAccessRights UnixMode removing DELETE scp 0x%p unix 0%o",
+                     scp, scp->unixModeBits);
+           *outRightsp &= ~PRSFS_DELETE;
+       }
+    }
+
+    /* if the user can insert, we must assume they can read/write as well
+     * because we do not have the ability to determine if the current user
+     * is the owner of the file. We will have to make the call to the
+     * file server and let the file server tell us if the request should
+     * be denied.
+     */
+    if ((*outRightsp & PRSFS_INSERT) && (scp->creator == userp))
+        *outRightsp |= PRSFS_READ | PRSFS_WRITE;
 
     /* if the user can obtain a write-lock, read-locks are implied */
     if (*outRightsp & PRSFS_WRITE)
@@ -104,9 +133,10 @@ int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *userp, afs_uint32
     /* fall through */
 
   done:
-    if (didLock) 
-        lock_ReleaseMutex(&aclScp->mx);
-    cm_ReleaseSCache(aclScp);
+    if (didLock)
+        lock_ReleaseRead(&aclScp->rw);
+    if (release)
+        cm_ReleaseSCache(aclScp);
     return code;
 }
 
@@ -126,40 +156,41 @@ long cm_GetAccessRights(struct cm_scache *scp, struct cm_user *userp,
     int got_cb = 0;
 
     /* pretty easy: just force a pass through the fetch status code */
-        
-    osi_Log2(afsd_logp, "GetAccess scp 0x%p user 0x%p", scp, userp);
+
+    osi_Log2(afsd_logp, "GetAccessRights scp 0x%p user 0x%p", scp, userp);
 
     /* first, start by finding out whether we have a directory or something
      * else, so we can find what object's ACL we need.
      */
-    if (scp->fileType == CM_SCACHETYPE_DIRECTORY ) {
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY || cm_accessPerFileCheck) {
        code = cm_SyncOp(scp, NULL, userp, reqp, 0,
                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_FORCECB);
-       if (!code) 
+       if (!code)
            cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    else
+        osi_Log3(afsd_logp, "GetAccessRights syncop failure scp %x user %x code %x", scp, userp, code);
     } else {
         /* not a dir, use parent dir's acl */
-        tfid.cell = scp->fid.cell;
-        tfid.volume = scp->fid.volume;
-        tfid.vnode = scp->parentVnode;
-        tfid.unique = scp->parentUnique;
-        lock_ReleaseMutex(&scp->mx);
-        code = cm_GetSCache(&tfid, &aclScp, userp, reqp);
+        cm_SetFid(&tfid, scp->fid.cell, scp->fid.volume, scp->parentVnode, scp->parentUnique);
+        lock_ReleaseWrite(&scp->rw);
+        code = cm_GetSCache(&tfid, NULL, &aclScp, userp, reqp);
         if (code) {
-            lock_ObtainMutex(&scp->mx);
+            lock_ObtainWrite(&scp->rw);
            goto _done;
-        }       
-                
-        osi_Log2(afsd_logp, "GetAccess parent scp %x user %x", aclScp, userp);
-       lock_ObtainMutex(&aclScp->mx);
+        }
+
+        osi_Log2(afsd_logp, "GetAccessRights parent scp %x user %x", aclScp, userp);
+       lock_ObtainWrite(&aclScp->rw);
        code = cm_SyncOp(aclScp, NULL, userp, reqp, 0,
                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_FORCECB);
        if (!code)
-           cm_SyncOpDone(aclScp, NULL, 
+           cm_SyncOpDone(aclScp, NULL,
                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-       lock_ReleaseMutex(&aclScp->mx);
+        else
+            osi_Log3(afsd_logp, "GetAccessRights parent syncop failure scp %x user %x code %x", aclScp, userp, code);
+       lock_ReleaseWrite(&aclScp->rw);
         cm_ReleaseSCache(aclScp);
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
     }
 
   _done: