windows-getaccessrights-20080805
[openafs.git] / src / WINNT / afsd / cm_access.c
index 9b1d0b0..90948cf 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <windows.h>
 #include <winsock2.h>
-#include <malloc.h>
 #include <string.h>
 #include <stdlib.h>
 #include <nb30.h>
@@ -20,6 +19,8 @@
 
 #include "afsd.h"
 
+int cm_deleteReadOnly = 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.
  *
@@ -36,44 +37,54 @@ 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 */
+
+#if 0
+    if (scp->flags & CM_SCACHEFLAG_EACCESS) {
+       *outRightsp = 0;
+       return 1;
+    }
+#endif
     didLock = 0;
     if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
-        aclScp = scp;
-        cm_HoldSCache(scp);
+        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) 
             return 0;
         if (aclScp != scp) {
-            code = lock_TryMutex(&aclScp->mx);
+            code = lock_TryRead(&aclScp->rw);
             if (code == 0) {
                 /* can't get lock safely and easily */
                 cm_ReleaseSCache(aclScp);
                 return 0;
             }
 
-            /* 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 == cm_data.rootSCachep)
+    {
+       *outRightsp = aclScp->anyAccess;
+    } else
+#endif
     if ((~aclScp->anyAccess & rights) == 0) {
         *outRightsp = rights;
     } else {
@@ -86,19 +97,46 @@ 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))
-        *outRightsp &= ~PRSFS_WRITE;
+    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 0x%x", 
+                     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) {
+           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)
+       *outRightsp |= PRSFS_LOCK;
 
     code = 1;
     /* fall through */
 
   done:
     if (didLock) 
-        lock_ReleaseMutex(&aclScp->mx);
-    cm_ReleaseSCache(aclScp);
+        lock_ReleaseRead(&aclScp->rw);
+    if (release)
+        cm_ReleaseSCache(aclScp);
     return code;
 }
 
@@ -119,51 +157,38 @@ long cm_GetAccessRights(struct cm_scache *scp, struct cm_user *userp,
 
     /* pretty easy: just force a pass through the fetch status code */
         
-    osi_Log2(afsd_logp, "GetAccess scp %x user %x", 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 (!cm_HaveCallback(scp)) {
+    if (scp->fileType == CM_SCACHETYPE_DIRECTORY ) {
        code = cm_SyncOp(scp, NULL, userp, reqp, 0,
-                     CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-       if (code) 
-           return code;
-
-       got_cb = 1;
-    }
-        
-    if (scp->fileType != CM_SCACHETYPE_DIRECTORY) {
+                        CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_FORCECB);
+       if (!code) 
+           cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    } 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);
+        cm_SetFid(&tfid, scp->fid.cell, scp->fid.volume, scp->parentVnode, scp->parentUnique);
+        lock_ReleaseWrite(&scp->rw);
         code = cm_GetSCache(&tfid, &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);
-       if (!code) {
-           code = cm_GetCallback(aclScp, userp, reqp, 1);
-           cm_SyncOpDone(aclScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-       }
-        lock_ReleaseMutex(&aclScp->mx);
+                        CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_FORCECB);
+       if (!code)
+           cm_SyncOpDone(aclScp, NULL, 
+                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+       lock_ReleaseWrite(&aclScp->rw);
         cm_ReleaseSCache(aclScp);
-        lock_ObtainMutex(&scp->mx);
-    } else if (!got_cb) {
-       code = cm_GetCallback(scp, userp, reqp, 1);
+        lock_ObtainWrite(&scp->rw);
     }
 
   _done:
-    if (got_cb)
-       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-
     return code;
 }